github get started
github get startedLF will be replaced by CRLF
LF will be replaced by CRLF
Git can auto-converting CRLF line endings into LF when you add a file to the index. Turn on this functionality with the core.autocrlf setting. If you’re on a Windows machine, set it to true – this converts LF endings into CRLF when you check out code: git config --global core.autocrlf true git config --global core.autocrlf false
Git for Absolute Beginners
Git for Absolute BeginnersActivity: Use the GitHub Desktop client
Version control systems Use the GitHub Desktop clientFollow a typical workflow with a GitHub project
Create a branch
Merge the development branch into master
Merge the branch through a pull request
Managing merge conflicts
Conclusion
Although most developers use the command line when working with version control systems, there are many GUI clients available that can potentially simplify the process. GUI clients might be especially helpful when you’re trying to see what has changed in a file since the GUI can quicklyFollow a typical workflow with a GitHub project
In this tutorial, you’ll use GitHub Desktop to manage the Git workflow. Rather than working in a GitHub wiki (as you did in the previous GitHub tutorial), you’ll work in a regular Git repository. This is because GitHub wikis have some limitations when it comes to making pull requests. To set up your Git repo using the GitHub Desktop client: First, download and install GitHub Desktop. Launch the app and sign in. (You should already have a GitHub account from previous tutorials, but if not, create one.) Go to Github.com and browse to the repository you created in the GitHub tutorial, but not the wiki. Just go to the main repo. (If you didn’t do the previous activity, just create a new repository.) While viewing your GitHub repo in the browser, click Clone or download and select Open in Desktop.Open in GitHub Desktop Open GitHub Desktop client and go to File > Clone Repository. In the confirmation dialog, select Open GitHub Desktop.app. GitHub Desktop should launch with a “Clone a Repository” dialog box about where to clone the repository. If desired, you can change the Local Path. Click the URL tab, and then paste in the clone URL. In the Local Path field, select where you want the repo cloned. For example:
Selecting paths for the repo in GitHub Desktop Click Clone. Go into the repository where GitHub Desktop cloned the repo (use your Finder or browse the folders with Finder or Explorer) and either add a simple text file with some content or make a change to an existing file. Go back to GitHub Desktop. You’ll see the new file you added in the list of uncommitted changes on the left.
Uncommitted changes shown In the list of changed files, the green + means you’ve added a new file. A yellow circle means you’ve modified an existing file. In the lower-left corner of the GitHub Desktop client (where it says “Summary” and “Description”), type a commit message, and then click Commit to master. When you commit the changes, the left pane no longer shows the list of uncommitted changes. However, you’ve committed the changes only locally. You still have to push the commit to the remote (origin) repository. (“origin” is the alias name that refers to the remote repository.) Click Push origin at the top. You’ll see GitHub Desktop show that it’s “Pushing to origin.”
If you view your repository online, you’ll see that the change you made has been pushed to the master branch on origin. You can also click the History tab in the GitHub Desktop client (instead of the Changes tab), or go to View > Show History to see the changes you previously committed. Although I prefer to use the terminal instead of the GitHub Desktop GUI, the GUI gives you an easier visual experience to see the changes made to a repository. You can use both the command line and Desktop client in combination, if you want.
Create a branch
Now let’s create a branch, make some changes, and see how the changes are specific to that branch. In the GitHub Desktop client, go to Branch > New Branch and create a new branch. Call it “development” branch, and click Create Branch.Creating a new branch When you create the branch, you’ll see the Current branch drop-down menu indicate that you’re working in that branch. Creating a branch copies the existing content (from the branch you’re currently in, master) into the new branch (development).
Working in a branch Using Finder or Explorer, browse to the file you created earlier and make a change to it, such as adding a new line with some text. Save the changes. Return to GitHub Desktop and notice that on the Changes tab, you have new modified files.
New files modified The file changes show deleted lines in red and new lines in green. The colors help you see what changed. Commit the changes using the options in the lower-left corner, and click Commit to development. Click Publish branch (on the top of the GitHub Desktop window) to make the local branch also available on origin (GitHub). (Remember, there are usually two versions of a branch — the local version and the remote version.) Switch back to your master branch (using the Branch drop-down option at the top of the GitHub Desktop client). Then look at your file (in your text editor, such as Sublime text). Note how the file changes you made while editing in the development branch don’t appear in your master branch. You usually create a new branch when you’re making extensive changes to your content. For example, suppose you want to revamp a section (“Section X”) in your docs. However, you might want to publish other updates before publishing the extensive changes in Section X. If you were working in the same branch, it would be difficult to selectively push updates on a few files outside of Section X without pushing updates you’ve made to files in Section X as well. Through branching, you can confine your changes to a specific version that you don’t push live until you’re ready to merge the changes into your master branch.
Merge the development branch into master
Now let’s merge the development branch into the master branch. In the GitHub Desktop client, switch to the branch you want to merge the development branch into. From the branch selector, select the master branch. Go to Branch > Merge into Current Branch. In the merge window, select the development branch, and then click Merge development into master.Merging into master If you look at your changed file, you should see the changes in the master branch. Then click Push origin to push the changes to origin. You will now see the changes reflected on the file on GitHub.
Merge the branch through a pull request
Now let’s merge the development branch into the master using a pull request workflow. We’ll pretend that we’ve cloned a repo managed by engineers, and we want to have the engineers merge in the development branch. (In other words, we might not have rights to merge branches into the master.) To do this, we’ll create a pull request. Just as you did in the previous section, switch to the development branch, make some updates to the content in a file, and then save and commit the changes. After committing the changes, click Push origin to push your changes to the remote version of the development branch on GitHub. In the GitHub Desktop client, while you have development branch selected, go to Branch > Create Pull Request. GitHub opens in the browser with the Pull Request form opened.Pull request The left-facing arrow (pointing from the development branch towards the master) indicates that the pull request (“PR”) wants to merge the development branch into the master branch. Describe the pull request, and then click Create pull request. At this point, engineers would get an email request asking for them to merge in the edits. Play the part of the engineer by going to the Pull requests tab (on GitHub) to examine and confirm the merge request. As long as the merge request doesn’t pose any conflicts, you’ll see a Merge pull request button.
Confirm merge request To see what changes you’re merging into master, you can click the Files changed tab (which appears on the secondary navigation bar near the top). Then click Merge pull request to merge in the branch, and click Confirm merge to complete the merge. Now let’s get the updates you merged into the masterbranch online into your local copy. In your GitHub Desktop GUI client, select the master branch, and then click the Fetch origin button. Fetch gets the latest updates from origin but doesn’t update your local working copy with the changes. After you click Fetch origin, the button changes to Pull Origin. Click Pull Origin to update your local working copy with the fetched updates. Now check your files and notice that the updates that were originally in the development branch now appear in master. For a more detailed tutorial in making pull requests using the GitHub interface, see Pull request workflows through GitHub. I include an extensive tutorial with pull requests because it will likely be a common workflow if you are contributing to an open-source project.
Managing merge conflicts
Suppose you make a change on your local copy of a file in the repository, and someone else changes the same file using the online GitHub.com browser interface. The changes conflict with each other. What happens? When you click Push origin from the GitHub Desktop client, you’ll see a message saying that the repository has been updated since you last pulled:“The repository has been updated since you last pulled. Try pulling before pushing.”The button that previously said “Push origin” now says “Pull origin.” Click Pull origin. You now get another error message that says,“We found some conflicts while trying to merge. Please resolve the conflicts and commit the changes.”If you decide to commit your changes, you’ll see a message that says:“Please resolve all conflicted files, commit, and then try syncing again.”The GitHub Desktop client displays an exclamation mark next to files with merge conflicts. Open up a conflict file and look for the conflict markers (<<<<<<< and >>>>>>>). For example, you might see this: <<<<<<< HEAD This is an edit I made locally. ======= This is an edit I made from the browser. >>>>>>> c163ead57f6793678dd41b5efeef372d9bd81035 (From the command line, you can also run git status to see which files have conflicts.) The content in HEAD shows your local changes. The content below the ======= shows changes made by elsewhere. Fix all the conflicts by adjusting the content between the content markers and then deleting the content markers. For example, update the content to this: This is an edit I made locally. Now you need to re-add the file to Git again. In the GitHub Desktop client, commit your changes to the updated files. Then click Push origin. The updates on your local get pushed to the remote without any more conflicts.Conclusion
The more you use GitHub, the more familiar you’ll become with the workflows you need. Git is a robust, powerful collaboration platform, and there are many commands and workflows and features that you could adopt for a variety of scenarios. Despite Git’s variety of commands and workflows, most likely the scenarios you’ll actually use are somewhat limited in scope and learnable without too much effort. Pretty soon, these workflows will become automatic. Although we’ve been using the GitHub Desktop client for this exercise, you can do all of this through the command line, and you’ll probably find it preferable that way. However, the GitHub Desktop client can be a good starting point as you transition into becoming more of a Git power user.git always asking for user credentials
fix git always asking for user credentials git remote set-url origin git@github.com:williamkpchan Look in Git configuration file. git config --listGit error:
“Please make sure you have the correct access rights and the repository exists” reason: git URL might have changed. action: # View existing remotes git remote -v # Change the 'origin' remote's URL git remote set-url origin https://github.com/williamkpchan/williamkpchan.github.ioupdate an existing github repo from a different computer
Run git clone https://github.com/your/repo to clone your project on your computer. It will create a new folder containing your Android project Copy your changed files in this new folder You can now commit your changes from this folder If it is your repository If the repository belongs to you, you can start committing changes on the new computer and then pushing them to master: git push -u origin master The origin is the name of the remote directory. If you use the clone command on your own repository the origin of the cloned repository will automatically be your github repository. It is essential that if you clone a repository so that it is on two different computers, you use the pull command (see below) before you start working. Otherwise, you will put one of your repositories out of synch with the “master” repository and you will need to use the “merge” command, which can be rather tedious.Git server
Github on my own server Glip for PHP to view a git repoGitHub Actions
GitHub Actions usage: git [--version] [--help] [-C <path>] [-c name=value] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p | --paginate | --no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>] <command> [<args>] These are common Git commands used in various situations: start a working area (see also: git help tutorial) clone Clone a repository into a new directory init Create an empty Git repository or reinitialize an existing one work on the current change (see also: git help everyday) add Add file contents to the index mv Move or rename a file, a directory, or a symlink reset Reset current HEAD to the specified state rm Remove files from the working tree and from the index examine the history and state (see also: git help revisions) bisect Use binary search to find the commit that introduced a bug grep Print lines matching a pattern log Show commit logs show Show various types of objects status Show the working tree status grow, mark and tweak your common history branch List, create, or delete branches checkout Switch branches or restore working tree files commit Record changes to the repository diff Show changes between commits, commit and working tree, etc merge Join two or more development histories together rebase Reapply commits on top of another base tip tag Create, list, delete or verify a tag object signed with GPG collaborate (see also: git help workflows) fetch Download objects and refs from another repository pull Fetch from and integrate with another repository or a local branch push Update remote refs along with associated objects 'git help -a' and 'git help -g' list available subcommands and some concept guides. See 'git help <command>' or 'git help <concept>' to read about a specific subcommand or concept.batch file push to github with username and password
https://coolaj86.com/articles/vanilla-devops-git-credentials-cheatsheet/ git config --global user.name "williamkpchan" git config --global user.email "williamkpchan@gmail.com" git init git status git push pauseGit to avoid typing username password
Two approaches can be used. SSH keys are a way to identify trusted computers, without involving passwords. One needs to generate an SSH key and add the public key to your GitHub account. A guide on how to set up SSH key can be found here But this is not the main focus for this article. The key question remains: Is there a way to skip typing my username and/password when using HTTPS in GitHub? The answer is yes. This is done by using credential helpers. And this is the second approach. Credential helpers basically tells Git to remember your GitHub username and password every time it talks to GitHub. The syntax is given by: git config credential.https://example.com.username myusername git config credential.helper “$helper $options” Therefore, credential helpers are external programs from which Git can request both usernames and passwords. Credential helpers are in two forms: cache which caches credentials in memory for a short period of time, and store which basically stores credentials indefinitely on disk. Once you have selected the helper, you can tell Git to use it by putting its name into the credential.helper variable. Find a helper: git help -a | grep credential-credential-foo 2. Read its description. git help credential-foo 3. Tell Git to use it. git config — global credential.helper foo Assuming you have a remote with the following URL https://github.com/adambajumba/MestEIT, update the Git configuration to use the helper whenever it needs authentication steps: $ git config --global \credential.https://github.com/myusername/mysecretproject.username \your_github_account_name$ git config --global \credential.https://github.com/adambajumba/MestEIT.adambajumba \IsaacJumba Note that the remote URL is appended with a trailing .username fragment which becomes the key and the GitHub username becomes the value.Once the username is set, map the helper: And you are done! That easy, right? $ git config --global core.askpass ~/.git_credential_helper.rb An example of how it works would be: $ git config credential.helper store $ git push http://example.com/repo.git Username: <type your username> Password: <type your password>[several days later] $ git push http://example.com/repo.git [your credentials are used automatically] In conclusion, the credential helper does not work in all versions of git but from version 1.8 and above. Working with SSH key passphrasesGit Tools - Credential Storage
If you use the SSH transport for connecting to remotes, it’s possible for you to have a key without a passphrase, which allows you to securely transfer data without typing in your username and password. However, this isn’t possible with the HTTP protocols – every connection needs a username and password. This gets even harder for systems with two-factor authentication, where the token you use for a password is randomly generated and unpronounceable. Fortunately, Git has a credentials system that can help with this. Git has a few options provided in the box: The default is not to cache at all. Every connection will prompt you for your username and password. The “cache” mode keeps credentials in memory for a certain period of time. None of the passwords are ever stored on disk, and they are purged from the cache after 15 minutes. The “store” mode saves the credentials to a plain-text file on disk, and they never expire. This means that until you change your password for the Git host, you won’t ever have to type in your credentials again. The downside of this approach is that your passwords are stored in cleartext in a plain file in your home directory. If you’re using a Mac, Git comes with an “osxkeychain” mode, which caches credentials in the secure keychain that’s attached to your system account. This method stores the credentials on disk, and they never expire, but they’re encrypted with the same system that stores HTTPS certificates and Safari auto-fills. If you’re using Windows, you can install a helper called “Git Credential Manager for Windows.” This is similar to the “osxkeychain” helper described above, but uses the Windows Credential Store to control sensitive information. It can be found at https://github.com/Microsoft/Git-Credential-Manager-for-Windows. You can choose one of these methods by setting a Git configuration value:$ git config --global credential.helper cache
Some of these helpers have options. The “store” helper can take a--file <path>
argument, which customizes where the plain-text file is saved (the default is~/.git-credentials
). The “cache” helper accepts the--timeout <seconds>
option, which changes the amount of time its daemon is kept running (the default is “900”, or 15 minutes). Here’s an example of how you’d configure the “store” helper with a custom file name:$ git config --global credential.helper 'store --file ~/.my-credentials'
Git even allows you to configure several helpers. When looking for credentials for a particular host, Git will query them in order, and stop after the first answer is provided. When saving credentials, Git will send the username and password to all of the helpers in the list, and they can choose what to do with them. Here’s what a.gitconfig
would look like if you had a credentials file on a thumb drive, but wanted to use the in-memory cache to save some typing if the drive isn’t plugged in:[credential] helper = store --file /mnt/thumbdrive/.git-credentials helper = cache --timeout 30000
Under the Hood
How does this all work? Git’s root command for the credential-helper system isgit credential
, which takes a command as an argument, and then more input through stdin. This might be easier to understand with an example. Let’s say that a credential helper has been configured, and the helper has stored credentials formygithost
. Here’s a session that uses the “fill” command, which is invoked when Git is trying to find credentials for a host:$ git credential fill (1) protocol=https (2) host=mygithost (3) protocol=https (4) host=mygithost username=bob password=s3cre7 $ git credential fill (5) protocol=https host=unknownhost Username for 'https://unknownhost': bob Password for 'https://bob@unknownhost': protocol=https host=unknownhost username=bob password=s3cre7
This is the command line that initiates the interaction. Git-credential is then waiting for input on stdin. We provide it with the things we know: the protocol and hostname. A blank line indicates that the input is complete, and the credential system should answer with what it knows. Git-credential then takes over, and writes to stdout with the bits of information it found. If credentials are not found, Git asks the user for the username and password, and provides them back to the invoking stdout (here they’re attached to the same console). The credential system is actually invoking a program that’s separate from Git itself; which one and how depends on thecredential.helper
configuration value. There are several forms it can take:
Configuration Value | Behavior |
---|---|
foo | Runs git-credential-foo |
foo -a --opt=bcd | Runs git-credential-foo -a --opt=bcd |
/absolute/path/foo -xyz | Runs /absolute/path/foo -xyz |
!f() { echo "password=s3cre7"; }; f | Code after ! evaluated in shell |
git-credential-cache
, git-credential-store
, and so on, and we can configure them to take command-line arguments.
The general form for this is “git-credential-foo [args] <action>.”
The stdin/stdout protocol is the same as git-credential, but they use a slightly different set of actions:
get
is a request for a username/password pair.
store
is a request to save a set of credentials in this helper’s memory.
erase
purge the credentials for the given properties from this helper’s memory.
For the store
and erase
actions, no response is required (Git ignores it anyway).
For the get
action, however, Git is very interested in what the helper has to say.
If the helper doesn’t know anything useful, it can simply exit with no output, but if it does know, it should augment the provided information with the information it has stored.
The output is treated like a series of assignment statements; anything provided will replace what Git already knows.
Here’s the same example from above, but skipping git-credential and going straight for git-credential-store:
$ git credential-store --file ~/git.store store (1)
protocol=https
host=mygithost
username=bob
password=s3cre7
$ git credential-store --file ~/git.store get (2)
protocol=https
host=mygithost
username=bob (3)
password=s3cre7
Here we tell git-credential-store
to save some credentials: the username “bob” and the password “s3cre7” are to be used when https://mygithost
is accessed.
Now we’ll retrieve those credentials.
We provide the parts of the connection we already know (https://mygithost
), and an empty line.
git-credential-store
replies with the username and password we stored above.
Here’s what the ~/git.store
file looks like:
https://bob:s3cre7@mygithost
It’s just a series of lines, each of which contains a credential-decorated URL.
The osxkeychain
and wincred
helpers use the native format of their backing stores, while cache
uses its own in-memory format (which no other process can read).
git-credential-store
and friends are separate programs from Git, it’s not much of a leap to realize that any program can be a Git credential helper.
The helpers provided by Git cover many common use cases, but not all.
For example, let’s say your team has some credentials that are shared with the entire team, perhaps for deployment.
These are stored in a shared directory, but you don’t want to copy them to your own credential store, because they change often.
None of the existing helpers cover this case; let’s see what it would take to write our own.
There are several key features this program needs to have:
The only action we need to pay attention to is get
; store
and erase
are write operations, so we’ll just exit cleanly when they’re received.
The file format of the shared-credential file is the same as that used by git-credential-store
.
The location of that file is fairly standard, but we should allow the user to pass a custom path just in case.
Once again, we’ll write this extension in Ruby, but any language will work so long as Git can execute the finished product.
Here’s the full source code of our new credential helper:
#!/usr/bin/env ruby
require 'optparse'
path = File.expand_path '~/.git-credentials' # (1)
OptionParser.new do |opts|
opts.banner = 'USAGE: git-credential-read-only [options] <action>'
opts.on('-f', '--file PATH', 'Specify path for backing store') do |argpath|
path = File.expand_path argpath
end
end.parse!
exit(0) unless ARGV[0].downcase == 'get' # (2)
exit(0) unless File.exists? path
known = {} # (3)
while line = STDIN.gets
break if line.strip == ''
k,v = line.strip.split '=', 2
known[k] = v
end
File.readlines(path).each do |fileline| # (4)
prot,user,pass,host = fileline.scan(/^(.*?):\/\/(.*?):(.*?)@(.*)$/).first
if prot == known['protocol'] and host == known['host'] and user == known['username'] then
puts "protocol=#{prot}"
puts "host=#{host}"
puts "username=#{user}"
puts "password=#{pass}"
exit(0)
end
end
Here we parse the command-line options, allowing the user to specify the input file.
The default is ~/.git-credentials
.
This program only responds if the action is get
and the backing-store file exists.
This loop reads from stdin until the first blank line is reached.
The inputs are stored in the known
hash for later reference.
This loop reads the contents of the storage file, looking for matches.
If the protocol, host, and username from known
match this line, the program prints the results to stdout and exits.
We’ll save our helper as git-credential-read-only
, put it somewhere in our PATH
and mark it executable.
Here’s what an interactive session looks like:
$ git credential-read-only --file=/mnt/shared/creds get
protocol=https
host=mygithost
username=bob
protocol=https
host=mygithost
username=bob
password=s3cre7
Since its name starts with “git-”, we can use the simple syntax for the configuration value:
$ git config --global credential.helper 'read-only --file /mnt/shared/creds'
As you can see, extending this system is pretty straightforward, and can solve some common problems for you and your team.
OR
We can directly copy the content of the public key file in the clipboard.
pbcopy < ~/.ssh/github-rahul-office.pub
pbcopy < ~/.ssh/github-rahul-personal.pub
pbcopy < ~/.ssh/id_rsa.pub
and then log in to your personal GitHub account:
Go to Settings
.
From the left side navigation, click SSH and GPG keys
.
Click on New SSH key
, name it (it's a good idea to name it after the computer you’re using it in), and paste the key you previously copied.
Click Add key
.
ssh-add
and add the path to the files containing your keys.
As shown below, we are adding keys for our main account and the second account we just created.ssh-add ~/.ssh/id_rsassh-add ~/.ssh/id_rsa_uraccount
~/.ssh/config
.
But by default, it will not exist, so we’ll need to create it by running the command touch ~/.ssh/config
.
You can use any text editor or IDE to open and edit the file.
I went with the terminal’s text editor vim.
I don’t use it frequently, and it does have a bit of a learning curve, so I tend to use a cheat sheet to navigate through it.
To open the file, use vim config
.# Account 1 (work or personal) - the default configHost github.com HostName github.com User git IdentityFile ~/.ssh/id_rsa # Account 2 (work or personal) - the config we are addingHost github-uraccount HostName github.com User git IdentityFile ~/.ssh/id_rsa_uraccountThe top part is the default configuration.
It comprises the following:github.com
)
Its host name (github.com
)
a user ID (git
)
its identity file (~/.ssh/id_rsa
)github-uraccount
) and the identity file (to the key we created earlier, ~/.ssh/id_rsa_uraccount
).
And that should do it.
Save and close the file using :wq
(if you are using vim).
git init
then go to GitHub and create a new repository.
When you get to the instructions under Existing Git Repo, you’d normally just copy and paste the commands to your terminal to add the repo as the remote to your local repo, but for this case, we need to replace “github.com” with the host we set up in our config file earlier.
So instead of the default host git@github.com
, we use git@github-uraccount
.git remote add origin git@github-uraccount:uraccount/repo_name.gitNow you can push to GitHub using, for example, the following:git add .git commit -m "Initial commit"git push -u origin master
git config
as shown below (to do it globally, add the flag -g
before user
).git config user.name "uraccount"git config user.email "uraccount@gmail.com"
npm run dev
in the terminal.
This command executes the dev
script in the package.json file and starts up the web application defined in the sample repository.
If you're following along with a different application type, enter the corresponding start command for that project.
When your application starts, the codespace recognizes the port the application is running on and displays a prompt to forward that port so you can connect to it.
Click Open in Browser to view your running application in a new tab.
haikus.json
file by double-clicking it in the File Explorer.
Edit the text
field of the first haiku to personalize the application with your own haiku.
Go back to the running application tab in your browser and refresh to see your changes.
If you've closed the tab, open the Ports panel and click the Open in browser icon for the running port.
fairyfloss
and install the fairyfloss extension.
Select the fairyfloss
theme by selecting it from the list.
Changes you make to your editor setup in the current codespace, such as theme and keyboard bindings, are synced automatically via Settings Sync to any other codespaces you open and any instances of Visual Studio Code that are signed into your GitHub account.
devcontainer.json
file and/or Dockerfile in your repository.
If you don't configure a container, Codespaces uses a default image, which has many languages and runtimes available.
For information on what the default image contains, see the vscode-dev-containers
repository.
Note: If you want to use Git hooks in your codespace and apply anything in the git template directory to your codespace, then you must set up hooks during step 4 after the container is created.
Since your repository is cloned onto the host VM before the container is created, anything in the git template directory will not apply in your codespace unless you set up hooks in your devcontainer.json
configuration file using the postCreateCommand
in step 4.
For more information, see "Step 4: Post-creation setup."
devcontainer.json
file.
You may see postCreateCommand
and postAttachCommand
run.
If you want to use Git hooks in your codespace, set up hooks using the devcontainer.json
lifecycle scripts, such as postCreateCommand
.
For more information, see the devcontainer.json
reference in the Visual Studio Code documentation.
If you have a public dotfiles repository for Codespaces, you can enable it for use with new codespaces.
When enabled, your dotfiles will be cloned to the container and the install script will be invoked.
For more information, see "Personalizing Codespaces for your account."
Finally, the entire history of the repository is copied down with a full clone.
During post-creation setup you'll still be able to use the integrated terminal and make edits to your files, but take care to avoid any race conditions between your work and the commands that are running.
Shift + Command + P
(Mac) / Ctrl + Shift + P
(Windows)).
If you exit your codespace without running the stop command (for example, closing the browser tab), or if you leave the codespace running without interaction, the codespace and its running processes will continue until a window of inactivity occurs, after which the codespace will stop.
By default, the window of inactivity is 30 minutes.
When you close or stop your codespace, all uncommitted changes are preserved until you connect to the codespace again.
GITHUB_TOKEN
, and your GitHub credentials will be used to authenticate.
git init
to create a new git repository.
git clone /path/to/repository
when using a remote server, your command will be
git clone username@host:/path/to/repository
Working Directory
which holds the actual files.
the second one is the Index
which acts as a staging area and
finally the HEAD
which points to the last commit you've made.
git add <filename>
git add *
This is the first step in the basic git workflow. To actually commit these changes use
git commit -m "Commit message"
Now the file is committed to the HEAD, but not in your remote repository yet.
git push origin master
Change master to whatever branch you want to push your changes to.
If you have not cloned an existing repository and want to connect your repository to a remote server, you need to add it with
git remote add origin <server>
Now you are able to push your changes to the selected remote server
git checkout -b feature_x
switch back to master
git checkout master
and delete the branch again
git branch -d feature_x
a branch is not available to others unless you push the branch to your remote repository
git push origin <branch>
git pull
in your working directory to fetch and merge remote changes.
to merge another branch into your active branch (e.g. master), use
git merge <branch>
in both cases git tries to auto-merge changes. Unfortunately, this is not always possible and results in conflicts.
You are responsible to merge those conflicts
manually by editing the files shown by git. After changing, you need to mark them as merged with
git add <filename>
before merging changes, you can also preview them by using
git diff <source_branch> <target_branch>
git tag 1.0.0 1b2e1d63ff
the 1b2e1d63ff stands for the first 10 characters of the commit id you want to reference with your tag. You can get the commit id by looking at the...
git log
You can add a lot of parameters to make the log look like what you want. To see only the commits of a certain author:
git log --author=bob
To see a very compressed log where each commit is one line:
git log --pretty=oneline
Or maybe you want to see an ASCII art tree of all the branches, decorated with the names of tags and branches:
git log --graph --oneline --decorate --all
See only which files have changed:
git log --name-status
These are just a few of the possible parameters you can use. For more, see
git log --help
git checkout -- <filename>
this replaces the changes in your working tree with the last content in HEAD. Changes already added to the index, as well as new files, will be kept.
If you instead want to drop all your local changes and commits, fetch the latest history from the server and point your local master branch at it like this
git fetch origin
git reset --hard origin/master
gitk
use colorful git output
git config color.ui true
show log on just one line per commit
git config format.pretty oneline
use interactive adding
git add -i
commit add
and commit actions
can be performed on this branch also.
--ammend
Syntax:
git commit --amend
git pull
command's default behavior.
The git pull
command is the shorthand for git fetch
and git merge
, which fetches and incorporates changes from a remote repository into the current branch.
Perhaps you want to merge a new branch to the master.
If so, Git would directly merge using fast-forward without going through git fetch
and git merge
commands.
The merge is only possible if there are no commits on master from when you've created the new branch.
git pull
Command
11. Select the Git Credential Manager Core as the default Git credential helper, and click Next.
Git credential helpers are external programs that Git can prompt for input data, like usernames and passwords.
These input data can be stored in memory for a limited time or stored on the disk.
Git Credential Manager Core is based on the .NET framework and will provide multi-factor HTTPS authentication with Git.
git
command below to verify Git Bash is installed and its current version (--version
).
git --version
git config
command to add your name (YourName
) as your git username (user.name
).
The git config
command administers configuration variables that control how Git looks and operates.
Pass the --global
option to the git config
command to define the configuration variable (YourName
) in the ~/.gitconfig file specifically.
git config --global user.name "YourName"
3. Now open the command prompt and run the below git config
command to add your email ("[email protected]"
) as your git user email (--global user.email
) in the ~/.gitconfig file.
git config --global user.email "[email protected]"
4. In the same command prompt window, run the below git config
command to list (--list
) all the configuration variables in Git.
git config --list
You can see below that even though you've added variables in the ~/.gitconfig file via different consoles, the variables are accessible and displayed in the command prompt.
ls
command both in Git Bash console and command prompt to list the files and folders in the working directory.
In the screenshots below, you can see that the Git Bash console returns an output, while the command prompt throws an error, saying the ‘ls' command is not recognized.
C:\Program Files\Git\usr\bin
and run the ls
command.
cd C:\Program Files\Git\usr\bin # Change directory to where Linux utilities are stored
ls # Linux command that lists all files and folders in the working directory
Below, you can see that you didn't get an error after running the ls
command this time, but the command returned results instead.
git push
, and on other commands as well.
The complete push story here is long and boring.
To shorten it a whole lot, git push
was implemented poorly.
origin/B
or local like master
).
That is, if the current branch B has upstream U, git rev-parse U
should work.
If it does not work—if it complains that U does not exist—then most of Git acts as though the upstream is not set at all.
A few commands, like git branch -vv
, will show the upstream setting but mark it as "gone".
push.default
is set to simple
or upstream
, the upstream setting will make git push
, used with no additional arguments, just work.
That's it—that's all it does for git push
.
But that's fairly significant, since git push
is one of the places where a simple typo causes major headaches.
If your push.default
is set to nothing
, matching
, or current
, setting an upstream does nothing at all for git push
.
(All of this assumes your Git version is at least 2.0.)
git fetch
git fetch
with no additional arguments, Git figures out which remote to fetch from by consulting the current branch's upstream.
If the upstream is a remote-tracking branch, Git fetches from that remote.
(If the upstream is not set or is a local branch, Git tries fetching origin
.)
git merge
and git rebase
toogit merge
or git rebase
with no additional arguments, Git uses the current branch's upstream.
So it shortens the use of these two commands.
git pull
git pull
anyway, but if you do, git pull
uses the upstream setting to figure out which remote to fetch from, and then which branch to merge or rebase with.
That is, git pull
does the same thing as git fetch
—because it actually runs git fetch
—and then does the same thing as git merge
or git rebase
, because it actually runs git merge
or git rebase
.
(You should usually just do these two steps manually, at least until you know Git well enough that when either step fails, which they will eventually, you recognize what went wrong and know what to do about it.)
git status
git status
can report the difference between your current branch and its upstream, in terms of commits.
If, as is the normal case, you are on branch B
with its upstream set to origin/B
, and you run git status
, you will immediately see whether you have commits you can push, and/or commits you can merge or rebase onto.
This is because git status
runs:
git rev-list --count @{u}..HEAD
: how many commits do you have on B
that are not on origin/B
?
git rev-list --count HEAD..@{u}
: how many commits do you have on origin/B
that are not on B
?
Setting an upstream gives you all of these things.
master
already has an upstream set?$ git clone git://some.host/path/to/repo.git
or similar, the last step Git does is, essentially, git checkout master
.
This checks out your local branch master
—only you don't have a local branch master
.
On the other hand, you do have a remote-tracking branch named origin/master
, because you just cloned it.
Git guesses that you must have meant: "make me a new local master
that points to the same commit as remote-tracking origin/master
, and, while you're at it, set the upstream for master
to origin/master
."
This happens for every branch you git checkout
that you do not already have.
Git creates the branch and makes it "track" (have as an upstream) the corresponding remote-tracking branch.
$ git checkout -b solaris
there is, as yet, no origin/solaris
.
Your local solaris
cannot track remote-tracking branch origin/solaris
because it does not exist.
When you first push the new branch:
$ git push origin solaris
that creates solaris
on origin
, and hence also creates origin/solaris
in your own Git repository.
But it's too late: you already have a local solaris
that has no upstream.
3.
--set-upstream
or -u
during the git push
.
That's what the message is telling you.
You don't have to do it like that.
Well, as we noted above, you don't have to do it at all, but let's say you want an upstream.
You have already created branch solaris
on origin
, through an earlier push, and as your git branch
output shows, you already have origin/solaris
in your local repository.
You just don't have it set as the upstream for solaris
.
To set it now, rather than during the first push, use git branch --set-upstream-to
.
The --set-upstream-to
sub-command takes the name of any existing branch, such as origin/solaris
, and sets the current branch's upstream to that other branch.
That's it—that's all it does—but it has all those implications noted above.
It means you can just run git fetch
, then look around, then run git merge
or git rebase
as appropriate, then make new commits and run git push
, without a bunch of additional fussing-around.
1.To be fair, it was not clear back then that the initial implementation was error-prone.
That only became clear when every new user made the same mistakes every time.
It's now "less poor", which is not to say "great".
2."Never" is a bit strong, but I find that Git newbies understand things a lot better when I separate out the steps, especially when I can show them what git fetch
actually did, and they can then see what git merge
or git rebase
will do next.
3.If you run your first git push
as git push -u origin solaris
—i.e., if you add the -u
flag—Git will set origin/solaris
as the upstream for your current branch if (and only if) the push succeeds.
So you should supply -u
on the first push.
In fact, you can supply it on any later push, and it will set or change the upstream at that point.
But I think git branch --set-upstream-to
is easier, if you forgot.
4.Measured by the Austin Powers / Dr Evil method of simply saying "one MILLLL-YUN", anyway.
git stash
anything you were working on (as it's unlikely to be in a state where it can be committed), and then you'd have to leave your current branch to create a new branch from master
and thus begin working on your new urgent task.
This is a fairly straightforward workflow, but there is a mild annoyance which is that I happen to git stash
a lot and I find when jumping over to a new branch to do some urgent work that I might end up git stash
‘ing a few more times along the way.
Ultimately, when I'm done with my urgent task and ready to go back to my other branch, I then have to sift through my stash to find the relevant one I want to pop.
OK so not that tragic considering git stash list
will indicate the branch on which the stash was taken (which helps), but I do then need to Google what the syntax is for popping a specific stash (e.g.
it's git stash apply stash@{n}
where n
is the index you want to apply.)
Note: for the life of me I wish I could remember the syntax but it just eludes me every time.
Oh, and then you have to think about whether you actually want to use apply
, which leaves the stashed changes in the stack, or if you meant to actually pop
the stashed content (git stash pop stash@{n}
) so it's properly removed from the stack.
This is where I was recently introduced to a concept in git referred to as a ‘worktree' (thanks Kiran).
git stash
is just plain simpler and easier for a human mind to reason about.
I'll leave that up to the reader to decide.
master
, then create a new branch for doing some work.
We'll then imagine that I have been given an urgent task that I must complete now and yet my current non-master branch is in such a state that I want to avoid just stashing everything.
Note: I use tmux to split my terminal into multiple windows, and this demonstration will require two windows (or two separate terminal instances if you're not using a screen multiplexer) for the sake of demonstration.
mkdir foo_project
cd foo_project
touch foo
git add foo
git commit -m "created foo file"
git checkout -b foo_contents
echo 123 > foo
git add -u
git commit -m "added content to foo"
Now I'll create a new file and stage it for committing, but I won't commit it (this is where we pretend my branch is in some hideously complex state).
git worktree add ../foo_hotfix
Note: you'll want to create the new worktree in a directory outside of your current repo's directory (just so there's a clear distinction).
At this point you'll find your current terminal is still in the same foo_contents
, but there is now a new directory called foo_hotfix
outside your current repo's directory.
cd ./foo_hotfix
(or cd ../foo_hotfix
if your new terminal is currently set to your main git repo directory)
git log
OK, so if you do a git log
you'll find that the worktree has a branch automatically created and named after the worktree (so the branch is called foo_hotfix
in my case).
The important thing to realize is that git worktree add
is a bit like git branch
in that it creates the new worktree from the current branch you're in.
Meaning that my foo_hotfix
branch has the "added content to foo" commit from the foo_contents
branch as that's where I ran the git worktree add
command from.
This is what git log
looks like for me in this new worktree:
* d374dcb (Integralist) - (HEAD -> foo_hotfix, foo_contents) added content to foo (2 minutes ago)
* 9ae3a7f (Integralist) - (master) created foo file (3 minutes ago)
don't want the commit d374dcb
in there as it's coming from a branch (foo_contents
) that's still in progress, and so I'll need to rebase out that commit:
git rebase -i 9ae3a7f
Note: the rebase editor opens and I change pick
to drop
to get rid of the commit.
Now at this point I have a new working directory that I can work in:
echo hotfix > baz
git add baz
git commit -m "some hotfix"
master
branch, but remember I'm still in the foo_hotfix
directory, so my main repo directory foo_project
(open in another terminal window) is still in the foo_contents
branch).
git checkout master
git merge foo_hotfix
master
.
I want to go back to my original repo directory and make sure I have the latest master
rebased in before continuing on with my foo_contents
work.
To remove the worktree you can either remove it using the git interface (e.g.
git worktree remove foo_hotfix
) or manually remove it (e.g.
cd ../ && rm ./foo_hotfix
), where git will, at some point in the future, internally run a prune and remove any references to this orphaned branch/working tree (you could also manually trigger that prune using git worktree prune
).
Note: if I do git worktree remove foo_hotfix
while currently residing inside the foo_hotfix
directory, I'll find that the .git
repository is removed from the directory.
foo_hotfix
directory and that's where I ran git worktree remove foo_hotfix
:
cd ../foo_project
git rebase master
< whoops! I need to stash my changes first †
git stash pop
† why yes, this does seem a bit strange considering that's what I was trying to avoid in the first place, but in this case it's a single ‘stash' and so a simple git stash pop
will suffice to get me back to where I need to be.
I can now continue working on my foo_contents
branch.
git init
, you initialize a local Git repository.
In general, the purpose is to synchronize this repo with a remote Git repo.
To be able to synchronize code with a remote repo, you need to specify where the remote repo exists.
The first step is to add remote repos to your project.
# Syntax to add a git remote
git remote add REMOTE-ID REMOTE-URL
By convention, the original / primary remote repo is called origin
.
Here’s a real example:
# Add remote 1: GitHub.
git remote add origin git@github.com:jigarius/toggl2redmine.git
# Add remote 2: BitBucket.
git remote add upstream git@bitbucket.org:jigarius/toggl2redmine.git
In the above example, we add the remote repository of a project called Toggl 2 Redmine found on GitHub.
Use the above command to add one or more remote Git repos – make sure that each repo has its unique ID, i.e.
origin
, upstream
in the above example.
# Change local branch.
git checkout BRANCH
# Configure local branch to track a remote branch.
git branch -u origin/BRANCH
Here, BRANCH
is the name of the remote branch, which is usually the same as your local branch.
# The syntax is: git remote set-url REMOTE-ID REMOTE-URL
git remote set-url upstream git@foobar.com:jigarius/toggl2redmine.git
$git remote -v
origin git@github.com:jigarius/toggl2redmine.git (fetch)
origin git@github.com:jigarius/toggl2redmine.git (push)
upstream git@bitbucket.org:jigarius/toggl2redmine.git (fetch)
upstream git@bitbucket.org:jigarius/toggl2redmine.git (push)
# The syntax is: git remote remove REMOTE-ID
git remote remove upstream
git push
command.
To do this, choose a remote ID which will refer to all the remotes.
I usually call it all
, but there are developers who prefer origin
.
The idea is to add all the remote repo URLs as “push URLs” to this remote.
Here’s what you do:
# Create a new remote called "all" with the URL of the primary repo.
git remote add all git@github.com:jigarius/toggl2redmine.git
# Re-register the remote as a push URL.
git remote set-url --add --push all git@github.com:jigarius/toggl2redmine.git
# Add a push URL to a remote.
This means that "git push" will also push to this git URL.
git remote set-url --add --push all git@bitbucket.org:jigarius/toggl2redmine.git
If you don’t want to create an extra remote named all
, you can skip the first command and use the remote origin
instead of all
in the subsequent command(s).
Now, you can push to all remote repositories with a single command!
# Replace BRANCH with the name of the branch you want to push.
git push all BRANCH
git pull
from multiple repos.
However, you can git fetch
from multiple repos with the following command:
git fetch --all
This will fetch information from all remote repos.
You can switch to the latest version of a branch on a particular remote with the command:
# Checkout the branch you want to work with.
git checkout BRANCH
# Reset the branch to match the state as on a specific remote.
git reset --hard REMOTE-ID/BRANCH
git push
to that remote as you usually do.
We can copy the public key either by opening the github-rahul-office.pub file in vim and then copying the content of it.
vim ~/.ssh/github-rahul-office.pub
vim ~/.ssh/github-rahul-personal.pub
OR
We can directly copy the content of the public key file in the clipboard.
pbcopy < ~/.ssh/github-rahul-office.pub
pbcopy < ~/.ssh/github-rahul-personal.pub
2. Paste the public key on Github
Sign in to Github Account
Goto Settings > SSH and GPG keys > New SSH Key
Paste your copied public key and give it a Title of your choice.
OR
Sign in to Github
Paste this link in your browser (https://github.com/settings/keys) or click here
Click on New SSH Key and paste your copied key.
#rahul-office account
Host github.com-rahul-office
HostName github.com
User git
IdentityFile ~/.ssh/github-rahul-office
#rahul-personal account
Host github.com-rahul-personal
HostName github.com
User git
IdentityFile ~/.ssh/github-rahul-personal
git clone git@github.com-{your-username}:{owner-user-name}/{the-repo-name}.git
[e.g.] git clone git@github.com-rahul-personal:rahul-personal/TestRepo.git
git config user.email "my_office_email@gmail.com"
git config user.name "Rahul Pandey"
git config user.email "my-personal-email@gmail.com"
git config user.name "Rahul Pandey"
Pick the correct pair for your repository accordingly.
To push or pull to the correct account we need to add the remote origin to the project
git remote add origin git@github.com-rahul-personal:rahul-personal
git remote add origin git@github.com-rahul-office:rahul-office
Now you can use:
git push
git pull
git checkout --orphan BRANCHNAME
This creates a new branch, unrelated to your current branch.
Each project should be in its own orphaned branch.
Now for whatever reason, git needs a bit of cleanup after an orphan checkout.
rm .git/index
rm -r *
Make sure everything is committed before deleting
Once the orphan branch is clean, you can use it normally.
# repo 1
git push origin master:master-1
# repo 2
git push origin master:master-2
cd some_empty_directory
git init
touch .gitignore
git add .gitignore
git commit -m empty
git tag EMPTY
Start your projects from empty.
git branch software EMPTY
git checkout software
echo "array board[8,8] of piece" > chess.prog
git add chess.prog
git commit -m "chess program"
git branch thesis EMPTY
git checkout thesis
echo "the meaning of meaning" > philosophy_doctorate.txt
git add philosophy_doctorate.txt
git commit -m "Ph.D"
git checkout software
echo "while not end_of_game do make_move()" >> chess.prog
git add chess.prog
git commit -m "improved chess program"
touch untracked_software_file.prog
git checkout thesis
ls
philosophy_doctorate.txt untracked_software_file.prog
git checkout EMPTY
ls
untracked_software_file.prog
rm -r *
(directory is now really empty, apart from the repository stuff!)
git checkout thesis
ls
philosophy_doctorate.txt
By ensuring that the directory was empty before checking out our new project we made sure there were no hanging untracked files from another project.
$ GIT_AUTHOR_DATE='2001-01-01:T01:01:01' GIT_COMMITTER_DATE='2001-01-01T01:01:01' git commit -m empty
If the same dates are specified whenever committing an empty repository, then independently created empty repository commits can have the same SHA1 code.
This allows two repositories to be created independently and then merged together into a single tree with a common root in one repository later.
# Create thesis repository.
# Merge existing chess repository branch into it
mkdir single_repo_for_thesis_and_chess
cd single_repo_for_thesis_and_chess
git init
touch .gitignore
git add .gitignore
GIT_AUTHOR_DATE='2001-01-01:T01:01:01' GIT_COMMITTER_DATE='2001-01-01:T01:01:01' git commit -m empty
git tag EMPTY
echo "the meaning of meaning" > thesis.txt
git add thesis.txt
git commit -m "Wrote my PH.D"
git branch -m master thesis
# It's as simple as this ...
git remote add chess ../chessrepository/.git
git fetch chess chess:chess
chess.prog
philosophy_doctorate.txt
have
chess/chess.prog
thesis/philosophy_doctorate.txt
In this case your untracked software file will be chess/untracked_software_file.prog
.
When working in the thesis
directory you should not be disturbed by untracked chess program files, and you may find occasions when you can work happily without deleting untracked files from other projects.
Also, if you want to remove untracked files from other projects, it will be quicker (and less prone to error) to dump an unwanted directory than to remove unwanted files by selecting each of them.
project1/master
project1/featureABC
project2/master
project2/featureXYZ
GITHUB_TOKEN
instead.
For more information, see "Automatic token authentication."
If these options are not possible, and you must create a personal access token, consider using another service such as the 1Password CLI to store your token securely, or 1Password's GitHub shell plugin to securely authenticate to GitHub CLI.
When using a personal access token in a script, you can store your token as a secret and run your script through GitHub Actions.
For more information, see "Encrypted secrets." You can also store your token as a Codespaces secret and run your script in Codespaces.
For more information, see "Managing encrypted secrets for your codespaces."
pending
until it is reviewed by an organization administrator.
Your token will only be able to read public resources until it is approved.
If you are an owner of the organization, your request is automatically approved.
For more information, see "Reviewing and revoking personal access tokens in your organization".
$ git clone https://github.com/USERNAME/REPO.git
Username: YOUR_USERNAME
Password: YOUR_TOKEN
Personal access tokens can only be used for HTTPS Git operations.
If your repository uses an SSH remote URL, you will need to switch the remote from SSH to HTTPS.
If you are not prompted for your username and password, your credentials may be cached on your computer.
You can update your credentials in the Keychain to replace your old password with the token.
Instead of manually entering your personal access token for every HTTPS Git operation, you can cache your personal access token with a Git client.
Git will temporarily store your credentials in memory until an expiry interval has passed.
You can also store the token in a plain text file that Git can read before every request.
For more information, see "Caching your GitHub credentials in Git."
HTTPS
as your preferred protocol for Git operations and answer "yes" to the prompt asking if you would like to authenticate to Git with your GitHub credentials.
Install GitHub CLI on macOS, Windows, or Linux.
In the command line, enter gh auth login
, then follow the prompts.
When prompted for your preferred protocol for Git operations, select HTTPS
.
When asked if you would like to authenticate to Git with your GitHub credentials, enter Y
.
For more information about authenticating with GitHub CLI, see gh auth login
.
$ brew install git
Install GCM using Homebrew:
$ brew tap microsoft/git
$ brew install --cask git-credential-manager-core
For MacOS, you don't need to run git config
because GCM automatically configures Git for you.
The next time you clone an HTTPS URL that requires authentication, Git will prompt you to log in using a browser window.
You may first be asked to authorize an OAuth app.
If your account or organization requires two-factor auth, you'll also need to complete the 2FA challenge.
Once you've authenticated successfully, your credentials are stored in the macOS keychain and will be used every time you clone an HTTPS URL.
Git will not require you to type your credentials in the command line again unless you change your credentials.
Install Git for Windows, which includes GCM.
For more information, see "Git for Windows releases" from its releases page.
We recommend always installing the latest version.
At a minimum, install version 2.29 or higher, which is the first version offering OAuth support for GitHub.
The next time you clone an HTTPS URL that requires authentication, Git will prompt you to log in using a browser window.
You may first be asked to authorize an OAuth app.
If your account or organization requires two-factor auth, you'll also need to complete the 2FA challenge.
Once you've authenticated successfully, your credentials are stored in the Windows credential manager and will be used every time you clone an HTTPS URL.
Git will not require you to type your credentials in the command line again unless you change your credentials.
Host somename
HostName your.favorite.machine.berkeley.edu
User theuser
PreferredAuthentications publickey
Then you can invoke `ssh somename` and it will pass in all of the above options.
SSH Agent
If you do not want to have to type your key's passphrase every time, you can load the key into your SSH agent once. The ssh-agent is usually automatically started on Linux, and you can load the key into your agent by typing `ssh-add`. If your key is in a non-standard location, you can manually specify it with `ssh-add /path/to/the/ssh/key`. On macOS, your agent uses your keychain, so pass in `-K` to ssh-add, e.g. `ssh-add -K` or `ssh-add -K /path/to/the/ssh/key`.
.ssh
directory and listing the contents.
$ cd ~/.ssh
$ ls
If you see id_rsa.pub
, you already have a key pair and don't need to create a new one.
If you don't see id_rsa.pub
, use the following command to generate a new key pair.
Make sure to replace your@email.com
with your own email address.
$ ssh-keygen -o -t rsa -C "your@email.com"
(The -o
option was added in 2014; if this command fails for you, just remove the -o
and try again)
When asked where to save the new key, hit enter to accept the default location.
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/username/.ssh/id_rsa):
You will then be asked to provide an optional passphrase.
This can be used to make your key even more secure, but for this lesson you can skip it by hitting enter twice.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
When the key generation is complete, you should see the following confirmation:
Your identification has been saved in /Users/username/.ssh/id_rsa.
Your public key has been saved in /Users/username/.ssh/id_rsa.pub.
The key fingerprint is:
01:0f:f4:3b:ca:85:d6:17:a1:7d:f0:68:9d:f0:a2:db your@email.com
The key's randomart image is:
+--[ RSA 2048]----+
| |
| |
| . E + |
| . o = . |
| . S = o |
| o.O . o |
| o .+ . |
| . o+.. |
| .+=o |
+-----------------+
The random art image is an alternate way to match keys but we won't be needing this.
cat
:
$ cat ~/.ssh/id_rsa.pub
The output should look something like this:
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA879BJGYlPTLIuc9/R5MYiN4yc/YiCLcdBpSdzgK9Dt0Bkfe3rSz5cPm4wmehdE7GkVFXrBJ2YHqPLuM1yx1AUxIebpwlIl9f/aUHOts9eVnVh4NztPy0iSU/Sv0b2ODQQvcy2vYcujlorscl8JjAgfWsO3W4iGEe6QwBpVomcME8IU35v5VbylM9ORQa6wvZMVrPECBvwItTY8cPWH3MGZiK/74eHbSLKA4PY3gM4GHI450Nie16yggEg2aTQfWA1rry9JYWEoHS9pJ1dnLqZU3k/8OWgqJrilwSoC5rGjgp93iu0H8T6+mEHGRQe84Nk1y5lESSWIbn6P636Bl3uQ== your@email.com
Copy the contents of the output to your clipboard.
Login to github.com and bring up your account settings by clicking the tools icon.
Start a new git repository Your first instinct, when you start to do something new, should begit init .A new repo from scratch
Create a directory to contain the project. Go into the new directory. Typegit init . Write some code. Typegit add to add the files. Typegit commit .A new repo from an existing project
Say you've got an existing project that you want to start tracking with git. Go into the directory containing the project. Typegit init . Typegit add to add all of the relevant files. You'll probably want to create a.gitignore file right away, to indicate all of the files you don't want to track. Usegit add .gitignore , too. Typegit commit . git remote add origin https://github.com/williamkpchan/stdrvest.git git branch -M main git push -u origin main Getting Started with GitHub PagesConnect it to github
You've now got a local git repository. You can use git locally, like that, if you want. But if you want the thing to have a home on github, do the following. Go to github. Log in to your account. Click the new repository button in the top-right. You'll have an option there to initialize the repository with a README file, but I don't. Click the “Create repository” button. Now, follow the second set of instructions, “Push an existing repository…”$ git remote add origin git@github.com:username/new_repo $ git push -u origin master Actually, the first line of the instructions will say$ git remote add origin https://github.com/username/new_repo But I usegit@github.com:username/new_repo rather thanhttps://github.com/username/new_repo , as the former is for use with ssh (if you set up ssh as I mentioned in “Your first time”, then you won't have to type your password every time you push things to github). If you use the latter construction, you'll have to type your github password every time you push to github.See What Branch You're On
Run this command: git statusList All Branches
NOTE: The current local branch will be marked with an asterisk (*). To seelocal branches , run this command:git branch To seeremote branches , run this command:git branch -r To seeall local and remote branches , run this command:git branch -a Create a New Branch
Run this command (replacingmy-branch-name with whatever name you want):git checkout -b my-branch-name You're now ready to commit to this branch.Switch to a Branch In Your Local Repo
Run this command:git checkout my-branch-name Switch to a Branch That Came From a Remote Repo
To get a list of all branches from the remote, run this command:git pull Run this command to switch to the branch:git checkout --track origin/my-branch-name Push to a Branch
If your local branchdoes not exist on the remote, run either of these commands:git push -u origin my-branch-name git push -u origin HEAD NOTE: HEAD is a reference to the top of the current branch, so it's an easy way to push to a branch of the same name on the remote. This saves you from having to type out the exact name of the branch! If your local branchalready exists on the remote, run this command:git push Merge a Branch
You'll want to make sure your working tree is clean and see what branch you're on. Run this command:git status First, you must check out the branch that you want to merge another branch into (changes will be merged into this branch). If you're not already on the desired branch, run this command:git checkout master NOTE: Replacemaster with another branch name as needed. Now you can merge another branch into the current branch. Run this command:git merge my-branch-name NOTE: When you merge, there may be a conflict. Refer toHandling Merge Conflicts (the next exercise) to learn what to do.Delete Branches
To delete aremote branch , run this command:git push origin --delete my-branch-name To delete alocal branch , run either of these commands:git branch -d my-branch-name git branch -D my-branch-name NOTE: The -d option only deletes the branch if it has already been merged. The -D option is a shortcut for --delete --force, which deletes the branch irrespective of its merged status.Working with Remotes
Showing Your RemotesRemote repositories are versions of your project that are hosted on the Internet or network somewhere. You can have several of them, each of which generally is either read-only or read/write for you. Collaborating with others involves managing these remote repositories and pushing and pulling data to and from them when you need to share work. Managing remote repositories includes knowing how to add remote repositories, remove remotes that are no longer valid, manage various remote branches and define them as being tracked or not, and more. In this section, we’ll cover some of these remote-management skills. Note Remote repositories can be on your local machine. It is entirely possible that you can be working with a “remote” repository that is, in fact, on the same host you are. The word “remote” does not necessarily imply that the repository is somewhere else on the network or Internet, only that it is elsewhere. Working with such a remote repository would still involve all the standard pushing, pulling and fetching operations as with any other remote.
Adding Remote Repositories
Fetching and Pulling from Your Remotes
Pushing to Your Remotes
Inspecting a Remote
Renaming and Removing RemotesShowing Your Remotes
To see which remote servers you have configured, you can run thegit remote command. It lists the shortnames of each remote handle you’ve specified. If you’ve cloned your repository, you should at least seeorigin — that is the default name Git gives to the server you cloned from:$ git clone https://github.com/schacon/ticgit Cloning into 'ticgit'... remote: Reusing existing pack: 1857, done. remote: Total 1857 (delta 0), reused 0 (delta 0) Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done. Resolving deltas: 100% (772/772), done. Checking connectivity... done. $ cd ticgit $ git remote origin You can also specify-v , which shows you the URLs that Git has stored for the shortname to be used when reading and writing to that remote:$ git remote -v origin https://github.com/schacon/ticgit (fetch) origin https://github.com/schacon/ticgit (push) If you have more than one remote, the command lists them all. For example, a repository with multiple remotes for working with several collaborators might look something like this.$ cd grit $ git remote -v bakkdoor https://github.com/bakkdoor/grit (fetch) bakkdoor https://github.com/bakkdoor/grit (push) cho45 https://github.com/cho45/grit (fetch) cho45 https://github.com/cho45/grit (push) defunkt https://github.com/defunkt/grit (fetch) defunkt https://github.com/defunkt/grit (push) koke git://github.com/koke/grit.git (fetch) koke git://github.com/koke/grit.git (push) origin git@github.com:mojombo/grit.git (fetch) origin git@github.com:mojombo/grit.git (push) This means we can pull contributions from any of these users pretty easily. We may additionally have permission to push to one or more of these, though we can’t tell that here. Notice that these remotes use a variety of protocols; we’ll cover more about this in Getting Git on a Server.Adding Remote Repositories
We’ve mentioned and given some demonstrations of how thegit clone command implicitly adds theorigin remote for you. Here’s how to add a new remote explicitly. To add a new remote Git repository as a shortname you can reference easily, rungit remote add <shortname> <url> :$ git remote origin $ git remote add pb https://github.com/paulboone/ticgit $ git remote -v origin https://github.com/schacon/ticgit (fetch) origin https://github.com/schacon/ticgit (push) pb https://github.com/paulboone/ticgit (fetch) pb https://github.com/paulboone/ticgit (push) Now you can use the stringpb on the command line in lieu of the whole URL. For example, if you want to fetch all the information that Paul has but that you don’t yet have in your repository, you can rungit fetch pb :$ git fetch pb remote: Counting objects: 43, done. remote: Compressing objects: 100% (36/36), done. remote: Total 43 (delta 10), reused 31 (delta 5) Unpacking objects: 100% (43/43), done. From https://github.com/paulboone/ticgit * [new branch] master -> pb/master * [new branch] ticgit -> pb/ticgit Paul’smaster branch is now accessible locally aspb/master — you can merge it into one of your branches, or you can check out a local branch at that point if you want to inspect it. We’ll go over what branches are and how to use them in much more detail in Git Branching.Fetching and Pulling from Your Remotes
As you just saw, to get data from your remote projects, you can run:$ git fetch <remote> The command goes out to that remote project and pulls down all the data from that remote project that you don’t have yet. After you do this, you should have references to all the branches from that remote, which you can merge in or inspect at any time. If you clone a repository, the command automatically adds that remote repository under the name “origin”. So,git fetch origin fetches any new work that has been pushed to that server since you cloned (or last fetched from) it. It’s important to note that thegit fetch command only downloads the data to your local repository — it doesn’t automatically merge it with any of your work or modify what you’re currently working on. You have to merge it manually into your work when you’re ready. If your current branch is set up to track a remote branch (see the next section and Git Branching for more information), you can use thegit pull command to automatically fetch and then merge that remote branch into your current branch. This may be an easier or more comfortable workflow for you; and by default, thegit clone command automatically sets up your localmaster branch to track the remotemaster branch (or whatever the default branch is called) on the server you cloned from. Runninggit pull generally fetches data from the server you originally cloned from and automatically tries to merge it into the code you’re currently working on. Note From Git version 2.27 onward,git pull will give a warning if thepull.rebase variable is not set. Git will keep warning you until you set the variable. If you want the default behavior of Git (fast-forward if possible, else create a merge commit):git config --global pull.rebase "false" If you want to rebase when pulling:git config --global pull.rebase "true" Pushing to Your Remotes
When you have your project at a point that you want to share, you have to push it upstream. The command for this is simple:git push <remote> <branch> . If you want to push yourmaster branch to yourorigin server (again, cloning generally sets up both of those names for you automatically), then you can run this to push any commits you’ve done back up to the server:$ git push origin master This command works only if you cloned from a server to which you have write access and if nobody has pushed in the meantime. If you and someone else clone at the same time and they push upstream and then you push upstream, your push will rightly be rejected. You’ll have to fetch their work first and incorporate it into yours before you’ll be allowed to push. See Git Branching for more detailed information on how to push to remote servers.Inspecting a Remote
If you want to see more information about a particular remote, you can use thegit remote show <remote> command. If you run this command with a particular shortname, such asorigin , you get something like this:$ git remote show origin * remote origin Fetch URL: https://github.com/schacon/ticgit Push URL: https://github.com/schacon/ticgit HEAD branch: master Remote branches: master tracked dev-branch tracked Local branch configured for 'git pull': master merges with remote master Local ref configured for 'git push': master pushes to master (up to date) It lists the URL for the remote repository as well as the tracking branch information. The command helpfully tells you that if you’re on themaster branch and you rungit pull , it will automatically merge the remote’smaster branch into the local one after it has been fetched. It also lists all the remote references it has pulled down. That is a simple example you’re likely to encounter. When you’re using Git more heavily, however, you may see much more information fromgit remote show :$ git remote show origin * remote origin URL: https://github.com/my-org/complex-project Fetch URL: https://github.com/my-org/complex-project Push URL: https://github.com/my-org/complex-project HEAD branch: master Remote branches: master tracked dev-branch tracked markdown-strip tracked issue-43 new (next fetch will store in remotes/origin) issue-45 new (next fetch will store in remotes/origin) refs/remotes/origin/issue-11 stale (use 'git remote prune' to remove) Local branches configured for 'git pull': dev-branch merges with remote dev-branch master merges with remote master Local refs configured for 'git push': dev-branch pushes to dev-branch (up to date) markdown-strip pushes to markdown-strip (up to date) master pushes to master (up to date) This command shows which branch is automatically pushed to when you rungit push while on certain branches. It also shows you which remote branches on the server you don’t yet have, which remote branches you have that have been removed from the server, and multiple local branches that are able to merge automatically with their remote-tracking branch when you rungit pull .Renaming and Removing Remotes
You can rungit remote rename to change a remote’s shortname. For instance, if you want to renamepb topaul , you can do so withgit remote rename :$ git remote rename pb paul $ git remote origin paul It’s worth mentioning that this changes all your remote-tracking branch names, too. What used to be referenced atpb/master is now atpaul/master . If you want to remove a remote for some reason — you’ve moved the server or are no longer using a particular mirror, or perhaps a contributor isn’t contributing anymore — you can either usegit remote remove orgit remote rm :$ git remote remove paul $ git remote origin Once you delete the reference to a remote this way, all remote-tracking branches and configuration settings associated with that remote are also deleted.remotes and pushing to multiple Git repositories
Two Minute VersionWorking with two or more Git repositories? No problem! In this tutorial, you’ll first learn to setup multiple Git remotes. Next, you’ll also learn to perform a “git push” to multiple Git repositories with a single command. As a programmer, one of the best things that has happened to me is Git! If you don’t know what Git is, you should probably read a paragraph about it before you continue. Git allows you to synchronize the code on your computer with code on a remote repo shared with other developers – usually team members. In this tutorial we will learn to configure one or more Git remotes and pushing code to them with a single command.
Prerequisites
Adding multiple remotes
Configure primary remote
Change remote URL
List all remotes
Remove a remote
Push to multiple remotes
Pull from multiple remotesTwo Minute Version
Define a git remote which will point to multiple git remotes. Say, we call it “all”:git remote add all REMOTE-URL-1 . Register 1st push URL:git remote set-url --add --push all REMOTE-URL-1 . Register 2nd push URL:git remote set-url --add --push all REMOTE-URL-2 . Push a branch to all the remotes withgit push all BRANCH – replaceBRANCH with a real branch name. You cannot pull from multiple remotes, but you can fetch updates from multiple remotes withgit fetch --all .Prerequisites
Working knowledge of Git –git init ,git pull ,git commit andgit push . Have write access to one or more remote Git repositories.Adding multiple remotes
When you dogit init , you initialize a local Git repository. In general, the purpose is to synchronize this repo with a remote Git repo. To be able to synchronize code with a remote repo, you need to specify where the remote repo exists. The first step is to add remote repos to your project.# Syntax to add a git remote git remote add REMOTE-ID REMOTE-URL By convention, the original / primary remote repo is calledorigin . Here’s a real example:# Add remote 1: GitHub. git remote add origin git@github.com:jigarius/toggl2redmine.git # Add remote 2: BitBucket. git remote add upstream git@bitbucket.org:jigarius/toggl2redmine.git In the above example, we add the remote repository of a project called found on GitHub. Use the above command to add one or more remote Git repos – make sure that each repo has its unique ID, i.e.origin ,upstream in the above example.Configure primary remote
Though you can add multiple remotes, usually, each branch of your project can be configured to track a single remote branch. You can setup a branch to track a remote branch as follows:# Change local branch. git checkout BRANCH # Configure local branch to track a remote branch. git branch -u origin/BRANCH Here,BRANCH is the name of the remote branch, which is usually the same as your local branch.Change remote URL
If you want to change the URL associated to a remote that you’ve already added, you can do it with the following command:# The syntax is: git remote set-url REMOTE-ID REMOTE-URL git remote set-url upstream git@foobar.com:jigarius/toggl2redmine.git List all remotes
To see a list of all remotes, simply use the following command:$git remote -v origin git@github.com:jigarius/toggl2redmine.git (fetch) origin git@github.com:jigarius/toggl2redmine.git (push) upstream git@bitbucket.org:jigarius/toggl2redmine.git (fetch) upstream git@bitbucket.org:jigarius/toggl2redmine.git (push) Remove a remote
If you’ve added a remote which you no longer require, you can remove it as follows:# The syntax is: git remote remove REMOTE-ID git remote remove upstream Push to multiple remotes
Now that you have a primary remote repo and other remotes as well, it’s time to configure the push. The objective is topush to multiple Git remotes with a singlegit push command. To do this, choose a remote ID which will refer to all the remotes. I usually call itall , but there are developers who preferorigin . The idea is to add all the remote repo URLs as “push URLs” to this remote. Here’s what you do:# Create a new remote called "all" with the URL of the primary repo. git remote add all git@github.com:jigarius/toggl2redmine.git # Re-register the remote as a push URL. git remote set-url --add --push all git@github.com:jigarius/toggl2redmine.git # Add a push URL to a remote. This means that "git push" will also push to this git URL. git remote set-url --add --push all git@bitbucket.org:jigarius/toggl2redmine.git If you don’t want to create an extra remote namedall , you can skip the first command and use the remoteorigin instead ofall in the subsequent command(s). Now, you can push to all remote repositories with a single command!# Replace BRANCH with the name of the branch you want to push. git push all BRANCH Pull from multiple remotes
It is not possible togit pull from multiple repos. However, you cangit fetch from multiple repos with the following command:git fetch --all This willfetch information from all remote repos. You can switch to the latest version of a branch on a particular remote with the command: # Checkout the branch you want to work with.git checkout BRANCH # Reset the branch to match the state as on a specific remote.git reset --hard REMOTE-ID/BRANCH Bad git config file .git/config
run command: git config --global user.name "williamkpchan" git config --global user.email williamkpchan@gmail.comThe "fatal: 'origin' does not appear
https://github.com/williamkpchan/stdrvest The "fatal: 'origin' does not appear to be a git repository" error occurs when you try to push code to a remote Git repository without telling Git the location of the remote repository. To solve this error, use the git remote add command to add a remote to your project. Manually tell Git where the remote version of our repository exists. Do this using the git remote add command: git remote add origin https://github.com/williamkpchan/stdrvest Let’s try to push our code again: git push -u origin mainGit Error - Unable to resolve reference refs/remotes/origin/master reference broken
To fix this error, remove the following file YOURPROJECT/.git/refs/remotes/origin/master, and then run git fetch to download it again. Execute the following command within your project’s directory. rm .git/refs/remotes/origin/master git fetchfatal: the remote end hung up unexpectedly
This is due to git/https buffer settings. Solution: Navigate to repo. Run this to increase the buffer to 500MB: git config http.postBuffer 524288000 Then, run your original command again.git ls-remote
remote: error: File big.html is 229.72 MB; this exceeds GitHub's file size limit of 100.00 MB remote: error: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com. error: failed to push some refs Displays references available in a remote repository along with the associated commit IDs git ls-remote From https://github.com/williamkpchan/stdrvest 73f683026f1b7eb75f457ee38b0f07d323dec7e5 HEAD 73f683026f1b7eb75f457ee38b0f07d323dec7e5 refs/heads/ git show-ref Displays references available in a local repository along with the associated commit IDs. git show-ref 454b0b3be972a18fdeedad5bca50c6b60ace6cd7 refs/heads/main 73f683026f1b7eb75f457ee38b0f07d323dec7e5 refs/remotes/origin/main把檔案從 Git 裡拔掉
用 filter-branch 指令應該是相對較方便的。 舉例來說,目前的 Commit 紀錄是這樣: current commits 我想要把所有 Commit 的 config/database.yml 這個檔案刪掉: git filter-branch --tree-filter "rm -f config/database.yml" Rewrite 27f6ed6da50dbee5adbb68102266a91dc097ad3f (7/7) (0 seconds passed, remaining 0 predicted) Ref 'refs/heads/master' was rewritten 這樣看起來好像刪掉了…假的,其實那些東西都還在,隨時都可以取消剛剛這個指令,把剛剛被刪的檔案救回來: $ git reset refs/original/refs/heads/master --hard HEAD is now at 27f6ed6 add dog 2 全部斷乾淨! 再重頭來一次: git filter-branch -f --tree-filter "rm -f config/database.yml" Rewrite 27f6ed6da50dbee5adbb68102266a91dc097ad3f (7/7) (1 seconds passed, remaining 0 predicted) Ref 'refs/heads/master' was rewritten 跟前面不太一樣,這次多加了 -f 參數,是因為要強制覆寫 filter-branch 的備份點。 這邊使用 filter-branch 指令把檔案從工作目錄裡移掉,這時候 database.yml 的確已不見,但還有好幾個跟資源回收有關的事情需要處理一下: $ rm .git/refs/original/refs/heads/master 這個檔案還對剛剛做的 filter-branch 動作念念不忘(也就是備份點啦),隨時可以透過它再跳回去,所以先斷這條線。 再來,念念不忘的還有 Reflog,所以它也要清一下: $ git reflog expire --all --expire=now 這個指令是要求 Reflog 現在立刻過期(不然預設要等 30 天)。 接著再用 git fsck 指令就可以看到很多 Unreachable 的物件了: $ git fsck --unreachable Checking object directories: 100% (256/256), done. unreachable tree c8da8b6accf7029a2fb89eed130365822692b603 unreachable commit ca40fc9b31c777b1d3434453448c945fa2ffae11 unreachable commit cd82f29acbdce60c7f5f6894619585bd445797b5 unreachable tree 9e941fe91d47bf5174bd5a3d3e73ff257598b0ca unreachable tree 5e01e02411507c504c77bca53c508a3174c9a06f unreachable tree 607f055180d1195c81e0534d264d131d5abfdc27 unreachable commit 1de207637a6eed2cc86507dca37a38c7a932e53c unreachable tree a21100f9f3aae37858cc84fd402663992ccca681 unreachable commit 27f6ed6da50dbee5adbb68102266a91dc097ad3f unreachable tree a618ce33da8d21bca841f18e6432fcabf15d4477 unreachable commit 2bab3e7aff03a30ed9f53b5a7d3e02e1c0fc8c7c unreachable tree 70c6b4db190a452b22c28998d7c2487efb8026b2 unreachable commit 382a2a5cec96b94e9c5cb42bf92b4b236f4ad8ac 最後,啟動 Git 的資源回收機制,請垃圾車來立刻把它們載走: $ git gc --prune=now Counting objects: 14, done. Delta compression using up to 4 threads. Compressing objects: 100% (12/12), done. Writing objects: 100% (14/14), done. Total 14 (delta 5), reused 0 (delta 0) 檢查一下: $ git fsck Checking object directories: 100% (256/256), done. Checking objects: 100% (14/14), done. 看來垃圾都載走了。 我們試試看用偷吃步能不能 Reset 得回去: $ git reset 27f6ed6 --hard fatal: ambiguous argument '27f6ed6': unknown revision or path not in the working tree. Use '--' to separate paths from revisions, like this: 'git <command> [<revision>...] -- [<file>...]' 看來不行了,Git 已經找不到原來的那個 SHA-1 值了。 提醒一下,如果這些內容已經推出去的話,別忘了最後再加一步 git push -f 把線上的紀錄蓋掉喔。 小結 檔案進了 Git 就跟得罪方丈一樣,想走沒那麼容易,需要全部都斷乾淨才行。 關於 Git 的資源回收的相關介紹,請參閱 https://stackoverflow.com/questions/31648386/how-to-trash-all-local-git-changes-and-revert-to-old-commitrevert Git LFS file
To revert a file tracked by Git LFS (Large File Storage) back to its original state, you'll need to follow these general steps: Ensure you have the necessary access and permissions: Make sure you have write access to the repository and the necessary permissions to modify files. Determine the original version: Identify the commit or version of the file that you want to revert to. You can use Git commands such as git log or a Git client to view the commit history and find the desired version. Retrieve the original version: Use Git to retrieve the original version of the file. You can do this using the git checkout command, specifying the commit or version you want to revert to, and the path to the file. For example: applescript git checkout-- ``` Replace ` ` with the commit hash or the branch/tag name, and ` ` with the path to the file within the repository. Note: This command will update the file in your local working directory to the specified version. If you want to revert the file for others as well, you'll need to push the changes back to the remote repository. Stage and commit the changes (optional): If you want to keep a record of the reversion, you can stage and commit the changes using Git. This step is optional but can be useful for tracking the history of the file or collaborating with others. git add git commit -m "Revert file to original version" ``` Replace ` ` with the path to the file you reverted. Push the changes (optional): If you've made a commit in the previous step and want to share the reversion with others, you need to push the changes to the remote repository using the appropriate Git command (e.g., git push). By following these steps, you should be able to revert the LFS file back to its original version. Remember to exercise caution when modifying files, especially if you're working in a collaborative environment. to revert the LFS file back to the original one
gitattributes usedgit lfs pull to download original file thengit lfs uninstall, after that removed the.gitattributes file and commit again. git lfs uninstall this removes hooks and smudge/clean filter configuration and this is only the beginning.git lfs ls-files — view lfs filesfor each file, use globs if you can:git rm --cached myfile.psd — "remove" the lfs filegit add myfile.psd — add the "normal" filegit commit -m "restore files from lfs" gitattributes - Defining attributes per path $GIT_DIR/info/attributes, .gitattributes DESCRIPTION Agitattributes file is a simple text file that givesattributes to pathnames. .gitattributes 是用來告訴 Git 此專案要客製化的部份,為什麼要客製呢,因為 LFS 的使用條件就是你必須要告訴 Git,”這個檔案是 LFS 檔,請用 LFS 的方式處理“,但我們不需要自己設定,透過 git lfs 指令操作即可。 其實不只大型檔案,所有的檔案都可以用 .gitattributes 來告訴 Git 該怎麼處理這個檔案。 Git LFS 原理 Each line ingitattributes file is of form:pattern attr1 attr2 ... That is, a pattern followed by an attributes list, separated by whitespaces. Leading and trailing whitespaces are ignored. Lines that begin with # are ignored. Patterns that begin with a double quote are quoted in C style. When the pattern matches the path in question, the attributes listed on the line are given to the path.展示 10 大 Git 命令
合并链接: https://dev.to/lydiahallie/cs-visualized-useful-git-commands-37p1 git merge、 git rebase、 git reset、 git revert、 git fetch、 git pull、 git reflog…… 这些 git 命令执行的究竟是什么任务吗?
Fast-forward (—ff)
No-fast-foward (—no-ff)
合并冲突
变基(Rebasing)
交互式变基(Interactive Rebase)
重置(Resetting)
软重置
硬重置
还原(Reverting)
拣选(Cherry-picking)
取回(Fetching)
拉取(Pulling)
Reflog使用 Git 时,在头脑里可视化地想象它会非常有用: 当我执行一个特定命令时,这些分支会如何交互,又会怎样影响历史记录? 为什么当我在 master 上执行硬重启,force push 到原分支以及 rimraf 我们的 .git 文件夹时,我的同事哭了? 我觉得创建一些最常用且最有用的 Git 命令的可视化示例会是一个完美的用例!下面我将介绍的很多命令都有可选参数——你可以使用这些参数来改变对应命令的行为。 而我的示例只会涵盖命令的默认行为,而不会添加(或添加太多)可选配置!
合并
拥有多个分支是很方便的,这样可以将不同的新修改互相隔离开,而且还能确保你不会意外地向生产代码推送未经许可或破损的代码修改。 但一旦这些修改得到了批准许可,我们就需要将其部署到我们的生产分支中! 可将一个分支的修改融入到另一个分支的一种方式是执行 git merge。 Git 可执行两种类型的合并: fast-forward 和 no-fast-forward。 现在你可能分不清,但我们马上就来看看它们的差异所在。Fast-forward (—ff)
在当前分支相比于我们要合并的分支没有额外的提交(commit)时,可以执行 fast-forward 合并。 Git 很懒,首先会尝试执行最简单的选项: fast-forward!这类合并不会创建新的提交,而是会将我们正在合并的分支上的提交直接合并到当前分支。完美!现在,我们在 dev 分支上所做的所有改变都合并到了 master 分支上。 那么 no-fast-forward 又是什么意思呢?
No-fast-foward (—no-ff)
如果你的当前分支相比于你想要合并的分支没有任何提交,那当然很好,但很遗憾现实情况很少如此!如果我们在当前分支上提交我们想要合并的分支不具备的改变,那么 git 将会执行 no-fast-forward 合并。 使用 no-fast-forward 合并时,Git 会在当前活动分支上创建新的 merging commit。 这个提交的父提交(parent commit)即指向这个活动分支,也指向我们想要合并的分支!没什么大不了的,完美的合并!现在,我们在 dev 分支上所做的所有改变都合并到了 master 分支上。
合并冲突
尽管 Git 能够很好地决定如何合并分支以及如何向文件添加修改,但它并不总是能完全自己做决定。 当我们想要合并的两个分支的同一文件中的同一行代码上有不同的修改,或者一个分支删除了一个文件而另一个分支修改了这个文件时,Git 就不知道如何取舍了。 在这样的情况下,Git 会询问你想要保留哪种选择?假设在这两个分支中,我们都编辑了 README.md 的第一行。如果我们想把 dev 合并到 master,就会出现一个合并冲突: 你想要标题是 Hello! 还是 Hey!? 当尝试合并这些分支时,Git 会向你展示冲突出现的位置。 我们可以手动移除我们不想保留的修改,保存这些修改,再次添加这个已修改的文件,然后提交这些修改。
完成!尽管合并冲突往往很让人厌烦,但这是合理的: Git 不应该瞎猜我们想要保留哪些修改。
变基(Rebasing)
我们刚看到可通过执行 git merge 将一个分支的修改应用到另一个分支。 另一种可将一个分支的修改融入到另一个分支的方式是执行 git rebase。 git rebase 会将当前分支的提交复制到指定的分支之上。完美,现在我们在 dev 分支上获取了 master 分支上的所有修改。 变基与合并有一个重大的区别: Git 不会尝试确定要保留或不保留哪些文件。 我们执行 rebase 的分支总是含有我们想要保留的最新近的修改!这样我们不会遇到任何合并冲突,而且可以保留一个漂亮的、线性的 Git 历史记录。 上面这个例子展示了在 master 分支上的变基。 但是,在更大型的项目中,你通常不需要这样的操作。 git rebase 在为复制的提交创建新的 hash 时会修改项目的历史记录。 如果你在开发一个 feature 分支并且 master 分支已经更新过,那么变基就很好用。 你可以在你的分支上获取所有更新,这能防止未来出现合并冲突。
交互式变基(Interactive Rebase)
在为提交执行变基之前,我们可以修改它们!我们可以使用交互式变基来完成这一任务。 交互式变基在你当前开发的分支上以及想要修改某些提交时会很有用。 在我们正在 rebase 的提交上,我们可以执行以下 6 个动作: reword: 修改提交信息; edit: 修改此提交; squash: 将提交融合到前一个提交中; fixup: 将提交融合到前一个提交中,不保留该提交的日志消息; exec: 在每个提交上运行我们想要 rebase 的命令; drop: 移除该提交。 很棒!这样我们就能完全控制我们的提交了。 如果你想要移除一个提交,只需 drop 即可。如果你想把多个提交融合到一起以便得到清晰的提交历史,那也没有问题!
交互式变基能为你在 rebase 时提供大量控制,甚至可以控制当前的活动分支。
重置(Resetting)
当我们不想要之前提交的修改时,就会用到这个命令。 也许这是一个 WIP 提交或者可能是引入了 bug 的提交,这时候就要执行 git reset。 git reset 能让我们不再使用当前台面上的文件,让我们可以控制 HEAD 应该指向的位置。软重置
软重置会将 HEAD 移至指定的提交(或与 HEAD 相比的提交的索引),而不会移除该提交之后加入的修改! 假设我们不想保留添加了一个 style.css 文件的提交 9e78i,而且我们也不想保留添加了一个 index.js 文件的提交 035cc。 但是,我们确实又想要保留新添加的 style.css 和 index.js 文件!这是软重置的一个完美用例。输入 git status 后,你会看到我们仍然可以访问在之前的提交上做过的所有修改。 这很好,这意味着我们可以修复这些文件的内容,之后再重新提交它们!
硬重置
有时候我们并不想保留特定提交引入的修改。 不同于软重置,我们应该再也无需访问它们。 Git 应该直接将整体状态直接重置到特定提交之前的状态: 这甚至包括你在工作目录中和暂存文件上的修改。Git 丢弃了 9e78i 和 035cc 引入的修改,并将状态重置到了 ec5be 的状态。
还原(Reverting)
另一种撤销修改的方法是执行 git revert。 通过对特定的提交执行还原操作,我们会创建一个包含已还原修改的新提交。 假设 ec5be 添加了一个 index.js 文件。 但之后我们发现其实我们再也不需要由这个提交引入的修改了。 那就还原 ec5be 提交吧!完美!提交 9e78i 还原了由提交 ec5be 引入的修改。 在撤销特定的提交时,git revert 非常有用,同时也不会修改分支的历史。
拣选(Cherry-picking)
当一个特定分支包含我们的活动分支需要的某个提交时,我们对那个提交执行 cherry-pick!对一个提交执行 cherry-pick 时,我们会在活动分支上创建一个新的提交,其中包含由拣选出来的提交所引入的修改。 假设 dev 分支上的提交 76d12 为 index.js 文件添加了一项修改,而我们希望将其整合到 master 分支中。 我们并不想要整个 dev 分支,而只需要这个提交!现在 master 分支包含 76d12 引入的修改了。
取回(Fetching)
如果你有一个远程 Git 分支,比如在 GitHub 上的分支,当远程分支上包含当前分支没有的提交时,可以使用取回。 比如当合并了另一个分支或你的同事推送了一个快速修复时。 通过在这个远程分支上执行 git fetch,我们就可在本地获取这些修改。 这不会以任何方式影响你的本地分支: fetch 只是单纯地下载新的数据而已。现在我们可以看到自上次推送以来的所有修改了。 这些新数据也已经在本地了,我们可以决定用这些新数据做什么了。
拉取(Pulling)
尽管 git fetch 可用于获取某个分支的远程信息,但我们也可以执行 git pull。 git pull 实际上是两个命令合成了一个: git fetch 和 git merge。 当我们从来源拉取修改时,我们首先是像 git fetch 那样取回所有数据,然后最新的修改会自动合并到本地分支中。很好,我们现在与远程分支完美同步了,并且也有了所有最新的修改!
Reflog
每个人都会犯错,但犯错其实没啥!有时候你可能感觉你把 git repo 完全搞坏了,让你想完全删了了事。 git reflog 是一个非常有用的命令,可以展示已经执行过的所有动作的日志。 包括合并、重置、还原,基本上包含你对你的分支所做的任何修改。如果你犯了错,你可以根据 reflog 提供的信息通过重置 HEAD 来轻松地重做! 假设我们实际上并不需要合并原有分支。 当我们执行 git reflog 命令时,我们可以看到这个 repo 的状态在合并前位于 HEAD@{1}。 那我们就执行一次 git reset,将 HEAD 重新指向在 HEAD@{1} 的位置。
我们可以看到最新的动作已被推送给 reflog。
git error
remote: error: exceeds GitHub's file size limit of 100.00 MB git reset --soft HEAD~24 git commit -m "New message for the combined commit" git push origin master -f The -f is actually required because of the rebase. Whenever you do a rebase you would need to do a force push because the remote branch cannot be fast-forwarded to your commit.Git常用命令行整理
Git -v查看git版本 Git config --global user.name xxx配置全局用户 注意后面xxx中间有空格需要加双引号 Git config --global user.email xxx配置全局邮箱 git config --global --list 查看配置清单 Cd默认打开用户文件夹 Cd d:/xxx打开D盘下xxx文件夹 Cd ..返回上一级文件夹 Git init在当前文件夹下新建仓库 Ls查看本地资源 Ls-a查看本地资源,可直接查看隐藏资源 ls -ltr查看当前文件夹下有几个仓库 Ls -altr查看当前文件夹下所有目录 注意没有下一级目录,只有当前的 Git status查看仓库的状态(文件状态 当前分支等 (红色未管理 绿色已暂存)) Echo "xxx" > xxx.txt log新建文件并将>前面的字符添加到文件中去 touch text.txt新建一个空文件到当前文件夹 Mkdir xxx新建文件夹xxx到当前目录 Cat 文件名.后缀查看文件内容,在当前git命令行显示 Vi 文件名.后缀查看文件内容,可以修改,以vim编辑器打开 输入i切换编辑状态 esc退出编辑切换命令状态 :wq保存退出编辑器 Git add xxx.xxx将文件添加到暂存区 git rm --cached xxx.xxx将暂存区的文件拿回来,回到未管理状态 mv file1.txt file5.txt 将当前文件夹下file1.tx文件重命名为file5.txt git add *.txt可以一次把所有后缀为txt的文件添加到暂存区 Git add . 将当前目录下所有文件夹添加到暂存区 git commit -m "指定提交的信息"将文件提交到仓库 git log 命令查看提交记录,包含:commit后面是每次提交有一个唯一的提交ID ,还有每次提交的作者 邮箱 ,提交的时间,备注的提交信息 Git log --oneline是查看提交信息的简洁版 reset命令有三种模式:软 硬 混合 后面跟的是要回退的版本ID HEAD表示当前版本 HEAD^表示上一个版本 HEAD指向的是分支的最新提交节点HEAD~ HEAD^表示的是分支最新版本的上一个版本 HEAD~1 2 3 4 5,HEAD~后面可以跟具体数字,代表当前版本之前第几个版本,1就是上一个,2就是上两个,以此类推 Git reset --soft id:表示回退到之前的某一个版本,并且保留工作区和暂存区的所有修改内容 Git reset --hard id:表示回退到之前的某一个版本,并且丢弃工作区和暂存区的所有修改内容 Git rest --mixed id:表示回退到之前的某一个版本,并且只保留工作区的修改内容,丢弃暂存区的修改内容,reset默认是这个模式 Cp -rf 仓库文件夹 目标文件夹 cp -rf learn-git repo-soft 新建一个文件夹 repo-soft并将仓库 learn-git复制到里面去,注意复制要在上级文件夹目录先 git ls-files查看暂存区的内容 git reflog命令查看操作历史记录 Git diff后面如果什么都不加的话,默认比较的是工作区和暂存区之间的差异内容,他会显示发生更改的文件以及更改的详细信息 git diff HEAD工作区和版本库之间的差异内容 git diff --cached 暂存区与版本库之间差异 git diff ID ID版本与版本之间的差异 git diff ID ID xxx.xxx版本与版本之间某个文件的差异 Git diff 分支名 分支名 分支与分支之间差异 Git rm 文件名:直接在工作区和暂存区中删除文件 Git rm -r *递归删除某个文件夹下所有目录及文件 可以使用>>来追加内容到文件中去 比如 echo "追加" >> 文件名,将追加两个字添加到文件里面 ssh-keygen -t rsa -b 4096(-t指定协议为rsa -b指定生成的大小为4096)回车(rsa是非对称加密) ssh密钥生成 tail -5 xxx查看某文件末尾5行内容 Git clone xxx克隆远程仓库到本地 xxx为仓库链接,分https 和ssh Git push推送本地更新到远程 Git pull拉取远程更新到本地 git remote add origin git@github.com:ZhuoWang-NXNX/first-repo.git ------origin就是远程仓库的别名 给远程添加别名 git remote -v查看一下当前仓库所对应的远程仓库的别名和地址 git push -u origin master:main 将本地master分支与远程main分支关联起来 推送本地仓库master分支所有内容到远程main分支 Git pull orgin main:master拉取远程main分支内容到本地master分支 Git branch可以查看当前分支 Git barnch +分支名 可以创建新的分支 Git checkout +分支名切换分支(这个也有切换文件或者目录到之前的状态的意思 如果文件名与分支名相同就会发生歧义,所以切换分支最好用下面那种 Git switch +分支名(2.23版本后新加的专门切换分支的命令) Git merge +要被合并的分支名合并分支 (当前所在的分支就是要合并过去的目标分支,先切换到目标分支再进行合并) git branch -d +要删除的分支名删除已合并的分支 git branch -D +要删除的分支名强制删除分支,不管是否已合并 it checkout -b 分支名称+具体节点的提交ID恢复分支 Alias xxx="命令语句"Alias可以将一段比较长的命令封装为一个xxx别名 也可用config文件 Git rebase 分支名重定基准 Ignoring files
You can configure Git to ignore files you don't want to check in to GitHub.Configuring ignored files for a single repository
You can create a .gitignore file in your repository's root directory to tell Git which files and directories to ignore when you make a commit. To share the ignore rules with other users who clone the repository, commit the .gitignore file in to your repository. GitHub maintains an official list of recommended .gitignore files for many popular operating systems, environments, and languages in the "github/gitignore" public repository. You can also use gitignore.io to create a .gitignore file for your operating system, programming language, or IDE. For more information, see "github/gitignore" and the "gitignore.io" site. Open TerminalTerminalGit Bash. Navigate to the location of your Git repository. Create a .gitignore file for your repository. touch .gitignore If the command succeeds, there will be no output. For an example .gitignore file, see "Some common .gitignore configurations" in the Octocat repository. If you want to ignore a file that is already checked in, you must untrack the file before you add a rule to ignore it. From your terminal, untrack the file. git rm --cached FILENAMEConfiguring ignored files for all repositories on your computer
You can tell Git to always ignore certain files or directories when you make a commit in any Git repository on your computer. For example, you could use this feature to ignore any temporary backup files that your text editor creates. To always ignore a certain file or directory, add it to a file named ignore that's located inside the directory ~/.config/git. By default, Git will ignore any files and directories that are listed in the global configuration file ~/.config/git/ignore. If the git directory and ignore file don't exist yet, you may need to create them.Excluding local files without creating a
If you don't want to create a .gitignore file to share with others, you can create rules that are not committed with the repository. You can use this technique for locally-generated files that you don't expect other users to generate, such as files created by your editor. Use your favorite text editor to open the file called .git/info/exclude within the root of your Git repository. Any rule you add here will not be checked in, and will only ignore files for your local repository. Open TerminalTerminalGit Bash. Navigate to the location of your Git repository. Using your favorite text editor, open the file .git/info/exclude..gitignore filegit-push - Update remote
DESCRIPTIONgit push [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-q | --quiet] [-v | --verbose] [-u | --set-upstream] [-o <string> | --push-option=<string>] [--[no-]signed|--signed=(true|false|if-asked)] [--force-with-lease[=<refname>[:<expect>]] [--force-if-includes]] [--no-verify] [<repository> [<refspec>…]]
OPTIONS
GIT URLS
REMOTES
Named remote in configuration file
Named file in$GIT_DIR/remotes
Named file in$GIT_DIR/branches
OUTPUT
NOTE ABOUT FAST-FORWARDS
EXAMPLES
SECURITY
CONFIGURATIONDESCRIPTION
Updates remote refs using local refs, while sending objects necessary to complete the given refs. You can make interesting things happen to a repository every time you push into it, by setting up hooks there. When the command line does not specify where to push with the<repository> argument,branch.*.remote configuration for the current branch is consulted to determine where to push. If the configuration is missing, it defaults to origin. When the command line does not specify what to push with<refspec>... arguments or--all ,--mirror ,--tags options, the command finds the default<refspec> by consultingremote.*.push configuration, and if it is not found, honorspush.default configuration to decide what to push (See git-config[1] for the meaning ofpush.default ). When neither the command-line nor the configuration specifies what to push, the default behavior is used, which corresponds to thesimple value forpush.default : the current branch is pushed to the corresponding upstream branch, but as a safety measure, the push is aborted if the upstream branch does not have the same name as the local one.OPTIONS
<repository> The "remote" repository that is the destination of a push operation. This parameter can be either a URL (see the section GIT URLS below) or the name of a remote (see the section REMOTES below). <refspec>… Specify what destination ref to update with what source object. The format of a <refspec> parameter is an optional plus+ , followed by the source object <src>, followed by a colon: , followed by the destination ref <dst>. The <src> is often the name of the branch you would want to push, but it can be any arbitrary "SHA-1 expression", such asmaster~4 orHEAD (see gitrevisions[7]). The <dst> tells which ref on the remote side is updated with this push. Arbitrary expressions cannot be used here, an actual ref must be named. Ifgit push [<repository>] without any<refspec> argument is set to update some ref at the destination with<src> withremote.<repository>.push configuration variable,:<dst> part can be omitted—such a push will update a ref that<src> normally updates without any<refspec> on the command line. Otherwise, missing:<dst> means to update the same ref as the<src> . If <dst> doesn’t start withrefs/ (e.g.refs/heads/master ) we will try to infer where inrefs/* on the destination <repository> it belongs based on the type of <src> being pushed and whether <dst> is ambiguous. If <dst> unambiguously refers to a ref on the <repository> remote, then push to that ref. If <src> resolves to a ref starting with refs/heads/ or refs/tags/, then prepend that to <dst>. Other ambiguity resolutions might be added in the future, but for now any other cases will error out with an error indicating what we tried, and depending on theadvice.pushUnqualifiedRefname configuration (see git-config[1]) suggest what refs/namespace you may have wanted to push to. The object referenced by <src> is used to update the <dst> reference on the remote side. Whether this is allowed depends on where inrefs/* the <dst> reference lives as described in detail below, in those sections "update" means any modifications except deletes, which as noted after the next few sections are treated differently. Therefs/heads/* namespace will only accept commit objects, and updates only if they can be fast-forwarded. Therefs/tags/* namespace will accept any kind of object (as commits, trees and blobs can be tagged), and any updates to them will be rejected. It’s possible to push any type of object to any namespace outside ofrefs/{tags,heads}/* . In the case of tags and commits, these will be treated as if they were the commits insiderefs/heads/* for the purposes of whether the update is allowed. I.e. a fast-forward of commits and tags outsiderefs/{tags,heads}/* is allowed, even in cases where what’s being fast-forwarded is not a commit, but a tag object which happens to point to a new commit which is a fast-forward of the commit the last tag (or commit) it’s replacing. Replacing a tag with an entirely different tag is also allowed, if it points to the same commit, as well as pushing a peeled tag, i.e. pushing the commit that existing tag object points to, or a new tag object which an existing commit points to. Tree and blob objects outside ofrefs/{tags,heads}/* will be treated the same way as if they were insiderefs/tags/* , any update of them will be rejected. All of the rules described above about what’s not allowed as an update can be overridden by adding an the optional leading+ to a refspec (or using--force command line option). The only exception to this is that no amount of forcing will make therefs/heads/* namespace accept a non-commit object. Hooks and configuration can also override or amend these rules, see e.g.receive.denyNonFastForwards in git-config[1] andpre-receive andupdate in githooks[5]. Pushing an empty <src> allows you to delete the <dst> ref from the remote repository. Deletions are always accepted without a leading+ in the refspec (or--force ), except when forbidden by configuration or hooks. Seereceive.denyDeletes in git-config[1] andpre-receive andupdate in githooks[5]. The special refspec: (or+: to allow non-fast-forward updates) directs Git to push "matching" branches: for every branch that exists on the local side, the remote side is updated if a branch of the same name already exists on the remote side.tag <tag> means the same asrefs/tags/<tag>:refs/tags/<tag> . --all --branches Push all branches (i.e. refs underrefs/heads/ ); cannot be used with other <refspec>. --prune Remove remote branches that don’t have a local counterpart. For example a remote branchtmp will be removed if a local branch with the same name doesn’t exist any more. This also respects refspecs, e.g.git push --prune remote refs/heads/*:refs/tmp/* would make sure that remoterefs/tmp/foo will be removed ifrefs/heads/foo doesn’t exist. --mirror Instead of naming each ref to push, specifies that all refs underrefs/ (which includes but is not limited torefs/heads/ ,refs/remotes/ , andrefs/tags/ ) be mirrored to the remote repository. Newly created local refs will be pushed to the remote end, locally updated refs will be force updated on the remote end, and deleted refs will be removed from the remote end. This is the default if the configuration optionremote.<remote>.mirror is set. -n --dry-run Do everything except actually send the updates. --porcelain Produce machine-readable output. The output status line for each ref will be tab-separated and sent to stdout instead of stderr. The full symbolic names of the refs will be given. -d --delete All listed refs are deleted from the remote repository. This is the same as prefixing all refs with a colon. --tags All refs underrefs/tags are pushed, in addition to refspecs explicitly listed on the command line. --follow-tags Push all the refs that would be pushed without this option, and also push annotated tags inrefs/tags that are missing from the remote but are pointing at commit-ish that are reachable from the refs being pushed. This can also be specified with configuration variablepush.followTags . For more information, seepush.followTags in git-config[1]. --[no-]signed --signed=(true|false|if-asked) GPG-sign the push request to update refs on the receiving side, to allow it to be checked by the hooks and/or be logged. Iffalse or--no-signed , no signing will be attempted. Iftrue or--signed , the push will fail if the server does not support signed pushes. If set toif-asked , sign if and only if the server supports signed pushes. The push will also fail if the actual call togpg --sign fails. See git-receive-pack[1] for the details on the receiving end. --[no-]atomic Use an atomic transaction on the remote side if available. Either all refs are updated, or on error, no refs are updated. If the server does not support atomic pushes the push will fail. -o <option> --push-option=<option> Transmit the given string to the server, which passes them to the pre-receive as well as the post-receive hook. The given string must not contain a NUL or LF character. When multiple--push-option=<option> are given, they are all sent to the other side in the order listed on the command line. When no--push-option=<option> is given from the command line, the values of configuration variablepush.pushOption are used instead. --receive-pack=<git-receive-pack> --exec=<git-receive-pack> Path to the git-receive-pack program on the remote end. Sometimes useful when pushing to a remote repository over ssh, and you do not have the program in a directory on the default $PATH. --[no-]force-with-lease --force-with-lease=<refname> --force-with-lease=<refname>:<expect> Usually, "git push" refuses to update a remote ref that is not an ancestor of the local ref used to overwrite it. This option overrides this restriction if the current value of the remote ref is the expected value. "git push" fails otherwise. Imagine that you have to rebase what you have already published. You will have to bypass the "must fast-forward" rule in order to replace the history you originally published with the rebased history. If somebody else built on top of your original history while you are rebasing, the tip of the branch at the remote may advance with their commit, and blindly pushing with--force will lose their work. This option allows you to say that you expect the history you are updating is what you rebased and want to replace. If the remote ref still points at the commit you specified, you can be sure that no other people did anything to the ref. It is like taking a "lease" on the ref without explicitly locking it, and the remote ref is updated only if the "lease" is still valid.--force-with-lease alone, without specifying the details, will protect all remote refs that are going to be updated by requiring their current value to be the same as the remote-tracking branch we have for them.--force-with-lease=<refname> , without specifying the expected value, will protect the named ref (alone), if it is going to be updated, by requiring its current value to be the same as the remote-tracking branch we have for it.--force-with-lease=<refname>:<expect> will protect the named ref (alone), if it is going to be updated, by requiring its current value to be the same as the specified value<expect> (which is allowed to be different from the remote-tracking branch we have for the refname, or we do not even have to have such a remote-tracking branch when this form is used). If<expect> is the empty string, then the named ref must not already exist. Note that all forms other than--force-with-lease=<refname>:<expect> that specifies the expected current value of the ref explicitly are still experimental and their semantics may change as we gain experience with this feature. "--no-force-with-lease" will cancel all the previous --force-with-lease on the command line. A general note on safety: supplying this option without an expected value, i.e. as--force-with-lease or--force-with-lease=<refname> interacts very badly with anything that implicitly runsgit fetch on the remote to be pushed to in the background, e.g.git fetch origin on your repository in a cronjob. The protection it offers over--force is ensuring that subsequent changes your work wasn’t based on aren’t clobbered, but this is trivially defeated if some background process is updating refs in the background. We don’t have anything except the remote tracking info to go by as a heuristic for refs you’re expected to have seen & are willing to clobber. If your editor or some other system is runninggit fetch in the background for you a way to mitigate this is to simply set up another remote: git remote add origin-push $(git config remote.origin.url) git fetch origin-push Now when the background process runsgit fetch origin the references onorigin-push won’t be updated, and thus commands like: git push --force-with-lease origin-push Will fail unless you manually rungit fetch origin-push . This method is of course entirely defeated by something that runsgit fetch --all , in that case you’d need to either disable it or do something more tedious like: git fetch # update 'master' from remote git tag base master # mark our base point git rebase -i master # rewrite some commits git push --force-with-lease=master:base master:master I.e. create abase tag for versions of the upstream code that you’ve seen and are willing to overwrite, then rewrite history, and finally force push changes tomaster if the remote version is still atbase , regardless of what your localremotes/origin/master has been updated to in the background. Alternatively, specifying--force-if-includes as an ancillary option along with--force-with-lease[=<refname>] (i.e., without saying what exact commit the ref on the remote side must be pointing at, or which refs on the remote side are being protected) at the time of "push" will verify if updates from the remote-tracking refs that may have been implicitly updated in the background are integrated locally before allowing a forced update. -f --force Usually, the command refuses to update a remote ref that is not an ancestor of the local ref used to overwrite it. Also, when--force-with-lease option is used, the command refuses to update a remote ref whose current value does not match what is expected. This flag disables these checks, and can cause the remote repository to lose commits; use it with care. Note that--force applies to all the refs that are pushed, hence using it withpush.default set tomatching or with multiple push destinations configured withremote.*.push may overwrite refs other than the current branch (including local refs that are strictly behind their remote counterpart). To force a push to only one branch, use a+ in front of the refspec to push (e.ggit push origin +master to force a push to themaster branch). See the<refspec>... section above for details. --[no-]force-if-includes Force an update only if the tip of the remote-tracking ref has been integrated locally. This option enables a check that verifies if the tip of the remote-tracking ref is reachable from one of the "reflog" entries of the local branch based in it for a rewrite. The check ensures that any updates from the remote have been incorporated locally by rejecting the forced update if that is not the case. If the option is passed without specifying--force-with-lease , or specified along with--force-with-lease=<refname>:<expect> , it is a "no-op". Specifying--no-force-if-includes disables this behavior. --repo=<repository> This option is equivalent to the <repository> argument. If both are specified, the command-line argument takes precedence. -u --set-upstream For every branch that is up to date or successfully pushed, add upstream (tracking) reference, used by argument-less git-pull[1] and other commands. For more information, seebranch.<name>.merge in git-config[1]. --[no-]thin These options are passed to git-send-pack[1]. A thin transfer significantly reduces the amount of sent data when the sender and receiver share many of the same objects in common. The default is--thin . -q --quiet Suppress all output, including the listing of updated refs, unless an error occurs. Progress is not reported to the standard error stream. -v --verbose Run verbosely. --progress Progress status is reported on the standard error stream by default when it is attached to a terminal, unless -q is specified. This flag forces progress status even if the standard error stream is not directed to a terminal. --no-recurse-submodules --recurse-submodules=check|on-demand|only|no May be used to make sure all submodule commits used by the revisions to be pushed are available on a remote-tracking branch. If check is used Git will verify that all submodule commits that changed in the revisions to be pushed are available on at least one remote of the submodule. If any commits are missing the push will be aborted and exit with non-zero status. If on-demand is used all submodules that changed in the revisions to be pushed will be pushed. If on-demand was not able to push all necessary revisions it will also be aborted and exit with non-zero status. If only is used all submodules will be pushed while the superproject is left unpushed. A value of no or using--no-recurse-submodules can be used to override the push.recurseSubmodules configuration variable when no submodule recursion is required. When using on-demand or only, if a submodule has a "push.recurseSubmodules={on-demand,only}" or "submodule.recurse" configuration, further recursion will occur. In this case, "only" is treated as "on-demand". --[no-]verify Toggle the pre-push hook (see githooks[5]). The default is --verify, giving the hook a chance to prevent the push. With --no-verify, the hook is bypassed completely. -4 --ipv4 Use IPv4 addresses only, ignoring IPv6 addresses. -6 --ipv6 Use IPv6 addresses only, ignoring IPv4 addresses.GIT URLS
In general, URLs contain information about the transport protocol, the address of the remote server, and the path to the repository. Depending on the transport protocol, some of this information may be absent. Git supports ssh, git, http, and https protocols (in addition, ftp and ftps can be used for fetching, but this is inefficient and deprecated; do not use them). The native transport (i.e. git:// URL) does no authentication and should be used with caution on unsecured networks. The following syntaxes may be used with them:ssh:// [<user>@ ]<host>[: <port>]/ <path-to-git-repo>git:// <host>[:<port>]/ <path-to-git-repo>http [s ]:// <host>[: <port>]/ <path-to-git-repo>ftp [s ]:// <host>[: <port>]/ <path-to-git-repo> An alternative scp-like syntax may also be used with the ssh protocol: [<user>@ ]<host>:/ <path-to-git-repo> This syntax is only recognized if there are no slashes before the first colon. This helps differentiate a local path that contains a colon. For example the local pathfoo:bar could be specified as an absolute path or./foo:bar to avoid being misinterpreted as an ssh url. The ssh and git protocols additionally support~ <username> expansion:ssh:// [<user>@ ]<host>[: <port>]/~ <user>/ <path-to-git-repo>git:// <host>[: <port>]/~ <user>/ <path-to-git-repo> [<user>@ ]<host>:~ <user>/ <path-to-git-repo> For local repositories, also supported by Git natively, the following syntaxes may be used:/path/to/repo.git/ file:///path/to/repo.git/ These two syntaxes are mostly equivalent, except when cloning, when the former implies--local option. See git-clone[1] for details.git clone ,git fetch andgit pull , but notgit push , will also accept a suitable bundle file. See git-bundle[1]. When Git doesn’t know how to handle a certain transport protocol, it attempts to use theremote- <transport> remote helper, if one exists. To explicitly request a remote helper, the following syntax may be used: <transport>::<address> where <address> may be a path, a server and path, or an arbitrary URL-like string recognized by the specific remote helper being invoked. See gitremote-helpers[7] for details. If there are a large number of similarly-named remote repositories and you want to use a different format for them (such that the URLs you use will be rewritten into URLs that work), you can create a configuration section of the form: [url "<actual-url-base>"] insteadOf = <other-url-base> For example, with this: [url "git://git.host.xz/"] insteadOf = host.xz:/path/to/ insteadOf = work: a URL like "work:repo.git" or like "host.xz:/path/to/repo.git" will be rewritten in any context that takes a URL to be "git://git.host.xz/repo.git". If you want to rewrite URLs for push only, you can create a configuration section of the form: [url "<actual-url-base>"] pushInsteadOf = <other-url-base> For example, with this: [url "ssh://example.org/"] pushInsteadOf = git://example.org/ a URL like "git://example.org/path/to/repo.git" will be rewritten to "ssh://example.org/path/to/repo.git" for pushes, but pulls will still use the original URL.REMOTES
The name of one of the following can be used instead of a URL as<repository> argument: a remote in the Git configuration file:$GIT_DIR/config , a file in the$GIT_DIR/remotes directory, or a file in the$GIT_DIR/branches directory. All of these also allow you to omit the refspec from the command line because they each contain a refspec which git will use by default.Named remote in configuration file
You can choose to provide the name of a remote which you had previously configured using git-remote[1], git-config[1] or even by a manual edit to the$GIT_DIR/config file. The URL of this remote will be used to access the repository. The refspec of this remote will be used by default when you do not provide a refspec on the command line. The entry in the config file would appear like this: [remote "<name>"] url = <URL> pushurl = <pushurl> push = <refspec> fetch = <refspec> The<pushurl> is used for pushes only. It is optional and defaults to<URL> . Pushing to a remote affects all defined pushurls or all defined urls if no pushurls are defined. Fetch, however, will only fetch from the first defined url if multiple urls are defined.Named file in
You can choose to provide the name of a file in$GIT_DIR/remotes $GIT_DIR/remotes . The URL in this file will be used to access the repository. The refspec in this file will be used as default when you do not provide a refspec on the command line. This file should have the following format: URL: one of the above URL formats Push: <refspec> Pull: <refspec>Push: lines are used by git push andPull: lines are used by git pull and git fetch. MultiplePush: andPull: lines may be specified for additional branch mappings.Named file in
You can choose to provide the name of a file in$GIT_DIR/branches $GIT_DIR/branches . The URL in this file will be used to access the repository. This file should have the following format: <URL>#<head><URL> is required;#<head> is optional. Depending on the operation, git will use one of the following refspecs, if you don’t provide one on the command line.<branch> is the name of this file in$GIT_DIR/branches and<head> defaults tomaster . git fetch uses: refs/heads/<head>:refs/heads/<branch> git push uses: HEAD:refs/heads/<head>OUTPUT
The output of "git push" depends on the transport method used; this section describes the output when pushing over the Git protocol (either locally or via ssh). The status of the push is output in tabular form, with each line representing the status of a single ref. Each line is of the form: <flag> <summary> <from> -> <to> (<reason>) If --porcelain is used, then each line of the output is of the form: <flag> \t <from>:<to> \t <summary> (<reason>) The status of up-to-date refs is shown only if --porcelain or --verbose option is used. flag A single character indicating the status of the ref: (space) for a successfully pushed fast-forward;+ for a successful forced update;- for a successfully deleted ref;* for a successfully pushed new ref;! for a ref that was rejected or failed to push; and= for a ref that was up to date and did not need pushing. summary For a successfully pushed ref, the summary shows the old and new values of the ref in a form suitable for using as an argument togit log (this is<old>..<new> in most cases, and<old>...<new> for forced non-fast-forward updates). For a failed update, more details are given: rejected Git did not try to send the ref at all, typically because it is not a fast-forward and you did not force the update. remote rejected The remote end refused the update. Usually caused by a hook on the remote side, or because the remote repository has one of the following safety options in effect:receive.denyCurrentBranch (for pushes to the checked out branch),receive.denyNonFastForwards (for forced non-fast-forward updates),receive.denyDeletes orreceive.denyDeleteCurrent . See git-config[1]. remote failure The remote end did not report the successful update of the ref, perhaps because of a temporary error on the remote side, a break in the network connection, or other transient error. from The name of the local ref being pushed, minus itsrefs/<type>/ prefix. In the case of deletion, the name of the local ref is omitted. to The name of the remote ref being updated, minus itsrefs/<type>/ prefix. reason A human-readable explanation. In the case of successfully pushed refs, no explanation is needed. For a failed ref, the reason for failure is described.NOTE ABOUT FAST-FORWARDS
When an update changes a branch (or more in general, a ref) that used to point at commit A to point at another commit B, it is called a fast-forward update if and only if B is a descendant of A. In a fast-forward update from A to B, the set of commits that the original commit A built on top of is a subset of the commits the new commit B builds on top of. Hence, it does not lose any history. In contrast, a non-fast-forward update will lose history. For example, suppose you and somebody else started at the same commit X, and you built a history leading to commit B while the other person built a history leading to commit A. The history looks like this: B / ---X---A Further suppose that the other person already pushed changes leading to A back to the original repository from which you two obtained the original commit X. The push done by the other person updated the branch that used to point at commit X to point at commit A. It is a fast-forward. But if you try to push, you will attempt to update the branch (that now points at A) with commit B. This does not fast-forward. If you did so, the changes introduced by commit A will be lost, because everybody will now start building on top of B. The command by default does not allow an update that is not a fast-forward to prevent such loss of history. If you do not want to lose your work (history from X to B) or the work by the other person (history from X to A), you would need to first fetch the history from the repository, create a history that contains changes done by both parties, and push the result back. You can perform "git pull", resolve potential conflicts, and "git push" the result. A "git pull" will create a merge commit C between commits A and B. B---C / / ---X---A Updating A with the resulting merge commit will fast-forward and your push will be accepted. Alternatively, you can rebase your change between X and B on top of A, with "git pull --rebase", and push the result back. The rebase will create a new commit D that builds the change between X and B on top of A. B D / / ---X---A Again, updating A with this commit will fast-forward and your push will be accepted. There is another common situation where you may encounter non-fast-forward rejection when you try to push, and it is possible even when you are pushing into a repository nobody else pushes into. After you push commit A yourself (in the first picture in this section), replace it with "git commit --amend" to produce commit B, and you try to push it out, because forgot that you have pushed A out already. In such a case, and only if you are certain that nobody in the meantime fetched your earlier commit A (and started building on top of it), you can run "git push --force" to overwrite it. In other words, "git push --force" is a method reserved for a case where you do mean to lose history.EXAMPLES
git push Works likegit push <remote> , where <remote> is the current branch’s remote (ororigin , if no remote is configured for the current branch).git push origin Without additional configuration, pushes the current branch to the configured upstream (branch.<name>.merge configuration variable) if it has the same name as the current branch, and errors out without pushing otherwise. The default behavior of this command when no <refspec> is given can be configured by setting thepush option of the remote, or thepush.default configuration variable. For example, to default to pushing only the current branch toorigin usegit config remote.origin.push HEAD . Any valid <refspec> (like the ones in the examples below) can be configured as the default forgit push origin .git push origin : Push "matching" branches toorigin . See <refspec> in the OPTIONS section above for a description of "matching" branches.git push origin master Find a ref that matchesmaster in the source repository (most likely, it would findrefs/heads/master ), and update the same ref (e.g.refs/heads/master ) inorigin repository with it. Ifmaster did not exist remotely, it would be created.git push origin HEAD A handy way to push the current branch to the same name on the remote.git push mothership master:satellite/master dev:satellite/dev Use the source ref that matchesmaster (e.g.refs/heads/master ) to update the ref that matchessatellite/master (most probablyrefs/remotes/satellite/master ) in themothership repository; do the same fordev andsatellite/dev . See the section describing<refspec>... above for a discussion of the matching semantics. This is to emulategit fetch run on themothership usinggit push that is run in the opposite direction in order to integrate the work done onsatellite , and is often necessary when you can only make connection in one way (i.e. satellite can ssh into mothership but mothership cannot initiate connection to satellite because the latter is behind a firewall or does not run sshd). After running thisgit push on thesatellite machine, you would ssh into themothership and rungit merge there to complete the emulation ofgit pull that were run onmothership to pull changes made onsatellite .git push origin HEAD:master Push the current branch to the remote ref matchingmaster in theorigin repository. This form is convenient to push the current branch without thinking about its local name.git push origin master:refs/heads/experimental Create the branchexperimental in theorigin repository by copying the currentmaster branch. This form is only needed to create a new branch or tag in the remote repository when the local name and the remote name are different; otherwise, the ref name on its own will work.git push origin :experimental Find a ref that matchesexperimental in theorigin repository (e.g.refs/heads/experimental ), and delete it.git push origin +dev:master Update the origin repository’s master branch with the dev branch, allowing non-fast-forward updates. This can leave unreferenced commits dangling in the origin repository. Consider the following situation, where a fast-forward is not possible: o---o---o---A---B origin/master \ X---Y---Z dev The above command would change the origin repository to A---B (unnamed branch) / o---o---o---X---Y---Z master Commits A and B would no longer belong to a branch with a symbolic name, and so would be unreachable. As such, these commits would be removed by agit gc command on the origin repository.SECURITY
The fetch and push protocols are not designed to prevent one side from stealing data from the other repository that was not intended to be shared. If you have private data that you need to protect from a malicious peer, your best option is to store it in another repository. This applies to both clients and servers. In particular, namespaces on a server are not effective for read access control; you should only grant read access to a namespace to clients that you would trust with read access to the entire repository. The known attack vectors are as follows:The victim sends "have" lines advertising the IDs of objects it has that are not explicitly intended to be shared but can be used to optimize the transfer if the peer also has them. The attacker chooses an object ID X to steal and sends a ref to X, but isn’t required to send the content of X because the victim already has it. Now the victim believes that the attacker has X, and it sends the content of X back to the attacker later. (This attack is most straightforward for a client to perform on a server, by creating a ref to X in the namespace the client has access to and then fetching it. The most likely way for a server to perform it on a client is to "merge" X into a public branch and hope that the user does additional work on this branch and pushes it back to the server without noticing the merge.) As in #1, the attacker chooses an object ID X to steal. The victim sends an object Y that the attacker already has, and the attacker falsely claims to have X and not Y, so the victim sends Y as a delta against X. The delta reveals regions of X that are similar to Y to the attacker.
CONFIGURATION
Everything below this line in this section is selectively included from the git-config[1] documentation. The content is the same as what’s found there: push.autoSetupRemote If set to "true" assume--set-upstream on default push when no upstream tracking exists for the current branch; this option takes effect with push.default options simple, upstream, and current. It is useful if by default you want new branches to be pushed to the default remote (like the behavior of push.default=current) and you also want the upstream tracking to be set. Workflows most likely to benefit from this option are simple central workflows where all branches are expected to have the same name on the remote. push.default Defines the actiongit push should take if no refspec is given (whether from the command-line, config, or elsewhere). Different values are well-suited for specific workflows; for instance, in a purely central workflow (i.e. the fetch source is equal to the push destination),upstream is probably what you want. Possible values are:nothing - do not push anything (error out) unless a refspec is given. This is primarily meant for people who want to avoid mistakes by always being explicit.current - push the current branch to update a branch with the same name on the receiving end. Works in both central and non-central workflows.upstream - push the current branch back to the branch whose changes are usually integrated into the current branch (which is called@{upstream} ). This mode only makes sense if you are pushing to the same repository you would normally pull from (i.e. central workflow).tracking - This is a deprecated synonym forupstream .simple - push the current branch with the same name on the remote. If you are working on a centralized workflow (pushing to the same repository you pull from, which is typicallyorigin ), then you need to configure an upstream branch with the same name. This mode is the default since Git 2.0, and is the safest option suited for beginners.matching - push all branches having the same name on both ends. This makes the repository you are pushing to remember the set of branches that will be pushed out (e.g. if you always push maint and master there and no other branches, the repository you push to will have these two branches, and your local maint and master will be pushed there). To use this mode effectively, you have to make sure all the branches you would push out are ready to be pushed out before running git push, as the whole point of this mode is to allow you to push all of the branches in one go. If you usually finish work on only one branch and push out the result, while other branches are unfinished, this mode is not for you. Also this mode is not suitable for pushing into a shared central repository, as other people may add new branches there, or update the tip of existing branches outside your control. This used to be the default, but not since Git 2.0 (simple is the new default). push.followTags If set to true, enable--follow-tags option by default. You may override this configuration at time of push by specifying--no-follow-tags . push.gpgSign May be set to a boolean value, or the string if-asked. A true value causes all pushes to be GPG signed, as if--signed is passed to git-push[1]. The string if-asked causes pushes to be signed if the server supports it, as if--signed=if-asked is passed to git push. A false value may override a value from a lower-priority config file. An explicit command-line flag always overrides this config option. push.pushOption When no--push-option=<option> argument is given from the command line,git push behaves as if each <value> of this variable is given as--push-option=<value> . This is a multi-valued variable, and an empty value can be used in a higher priority configuration file (e.g..git/config in a repository) to clear the values inherited from a lower priority configuration files (e.g.$HOME/.gitconfig ). Example: /etc/gitconfig push.pushoption = a push.pushoption = b ~/.gitconfig push.pushoption = c repo/.git/config push.pushoption = push.pushoption = b This will result in only b (a and c are cleared). push.recurseSubmodules May be "check", "on-demand", "only", or "no", with the same behavior as that of "push --recurse-submodules". If not set, no is used by default, unless submodule.recurse is set (in which case a true value means on-demand). push.useForceIfIncludes If set to "true", it is equivalent to specifying--force-if-includes as an option to git-push[1] in the command line. Adding--no-force-if-includes at the time of push overrides this configuration setting. push.negotiate If set to "true", attempt to reduce the size of the packfile sent by rounds of negotiation in which the client and the server attempt to find commits in common. If "false", Git will rely solely on the server’s ref advertisement to find commits in common. push.useBitmaps If set to "false", disable use of bitmaps for "git push" even ifpack.useBitmaps is "true", without preventing other git operations from using bitmaps. Default is true.Git Push
https://docs.gitopia.com/gitguides/git-push/index.htmlgit push is the git command used to upload the contents of a local repository to the corresponding remote repository. git push updates the remote branch with local commits. It is one of the four commands in Git that prompts interaction with the remote repository. Pushing is capable of overwriting changes; caution should be taken when pushing.git push is most commonly used to publish an upload local changes to a central repository. After a local repository has been modified a push is executed to share the modifications with remote team members.remember to commit bufore push or fail git commit -m "update" git push origin main This command creates a new branch and also switches to it. git checkout -b main // Switched to a new branch 'main'Git Push Syntax
git push <option> [<Remote URL><branch name><refspec>...]
Git Push Common Usage git push <remote> <branch> : Push the specified branch, along with all of the necessary commits and internal objects. This creates a local branch in the destination repository. To prevent you from overwriting commits, Git won’t let you push when it results in a non-fast-forward merge in the destination repository.Example
git push origin master git push <remote> --force : Force a push that would otherwise be blocked, usually because it will delete or overwrite existing commits. Do not use the--force flag unless you’re absolutely sure you know what you’re doing.Example
git push origin --force git push <remote> --all : Push all of your local branches to the specified remote.Example
git push origin --all git push <remote> --tags : Push all local tags that aren't yet in the remote repositoryExample
git push origin --tags git push <remote> --delete <branch-name> : Delete a specific remote branchExample
git push origin --delete dev3 Output: To gitopia://gitopia147dgrtq5ywww473uz680fx2ucex9fv3qnw94zm/hello-world - [deleted] dev3 You can learn more about thegit push command and its options in git-scm's documentation.Git list branches
When listing branches in git, it’s important to know the difference between local and remote branches, understand which branch you are currently on, and understand the branch tree. This guide will walk through all the different intricacies of Git branches.Listing the different types of git branches
List Local Branches
Get current git branchWorking with remote branches
List all remote branches
Git branch list all
Git branch treeFiltering and formatting branch listings
Git branch list format
Git list branch names
Git command for branch list
Git list all origin branchesTroubleshooting
Git branch command not showing all branches
Git branch not showing current branch
Git command get branch name
Listing the different types of git branches List Local Branches : To see a list of your local branches, run:git branch This command displays all local branches. The current branch will be highlighted and marked with an asterisk.Get current git branch : To find out which branch you are currently on:git branch --show-current Alternatively, use:git rev-parse --abbrev-ref HEAD
Working with remote branches List all remote branches : To view branches on your remote repositories:git branch -r This shows you all branches that you've fetched from your remote.Advanced branch listings
Git branch list all : To see both local and remote branches:git branch -a Git branch tree : While Git does not have a built-in tree view for branches, you can use thegit log --graph command to get a tree-like representation of the commit history.
Filtering and formatting branch listings Git branch list format : Customize the output format of the branch listing using the-format option:git branch --format="%(refname:short) %(upstream:short) %(contents:subject)" This example shows the branch name, its upstream branch, and the subject of the latest commit.Git list branch names : If you're only interested in the names of the branches without any additional info, sticking withgit branch orgit branch -a for all branches is your best bet.Git command for branch list with patterns: to list branches that match a certain pattern run:git branch --list '*pattern*' The pattern provided will act as a shell wildcard. If multiple are provided, the command will return all branches matching any of the patterns.Git list all origin branches : In order to specifically list all branches from theorigin remote, run:git branch -r | grep 'origin/'
Troubleshooting Git branch command not showing all branches : Ifgit branch doesn't show expected branches, ensure you've fetched the latest updates from your remote:git fetch --all Git branch not showing current branch : Ensure you're in a Git repository and not in a detached HEAD state. Usegit branch --show-current to attempt to display the current branch.Git command get branch name :git rev-parse --abbrev-ref HEAD This is a straightforward way to get the current branch name for scripting purposes. For further reading please see the official git documentation on git branches.git branch
lists branches in an arbitrary orderuses git log
list output in a tree like fasion git log --graph --pretty=oneline --abbrev-commit master |-- foo |-- foo1 |-- foo2 |-- bar |-- bar4using git log --graph
display the tag name and branch name git config --global alias.scripts "log --graph git scriptsdeploy website using github
deploy website using github一些git操作技巧集合
1 git remote update 2 git stash
创建一个stash:
查看stash列表:
应用stash:
清理stash:3 .gitignore和.gitkeep
.gitignore 文件
创建 .gitignore 文件
示例
使用 .gitignore 文件
.gitkeep 文件
创建 .gitkeep 文件
示例4 git patch
什么是补丁文件?
Git生成补丁文件的方法
使用 git diff
使用 git format-patch
生成单个补丁文件
生成一系列补丁文件
应用补丁文件5 git squash
为什么使用 git squash?
如何使用 git squash6 git submodule status
什么是Git子模块?
为什么要使用 git submodule status?
如何使用 git submodule status
示例7 git blame
什么是 git blame?
为什么使用 git blame?
如何使用 git blame
基本用法
示例输出
更多选项
实际场景中的应用8 git status | grep ... 结语
最基本的git操作无非包括git add、git commit、git checkout、git pull、git push,但是除此之外工作中还会应用到很多其他的git操作!当你使用Git进行版本控制时,你可能会和其他人一起协作开发一个项目。 在这种情况下,你需要与远程仓库保持同步,确保你能获取到其他团队成员所做的更改。 每次开始创建分支或者计划提交之前,最好使用git remote update来更新一下远端的分支信息到本地,以防止未更新而基于旧的版本进行开发,避免完成工作之后merge冲突等问题。
1 git remote update git stash 是一个非常有用的命令,它帮助你在处理一些临时的工作或者当你需要切换到另一个任务时,能够暂时“隐藏”你当前的工作进度。 想象一下,你正在写一篇文章,突然接到一个紧急电话,需要立刻去处理别的事情。 这时候,你不想丢失已经写下的内容,但又不得不马上离开。 Git stash 就像是快速保存你的工作草稿,等你回来后可以继续从你停下的地方开始。
2 git stash 创建一个stash:
当你有一些未提交的改动,并且想暂时把这些改动放到一边,你可以使用 git stash save <message> 命令。 这里的 <message> 是可选的,用来描述这次stash的内容。 如果不加任何消息,默认也会创建一个stash。 git stash save "暂时保存未完成的功能"查看stash列表:
你可以使用 git stash list 查看所有已有的stash列表,每个stash都有一个编号和描述信息。 git stash list应用stash:
如果你想把某个stash应用回你的工作目录,可以使用 git stash apply <stash>。 如果你只写了 git stash apply,默认会应用最近的一次stash。 git stash apply 或者如果你想在应用的同时删除stash(类似于“一次性使用”),可以使用 git stash pop。 git stash pop清理stash:
如果你不再需要某些stash了,可以使用 git stash drop <stash> 来删除特定的stash。 如果你想清除所有的stash,可以使用 git stash clear。 git stash clear当你在使用Git管理项目的时候,经常会遇到一些文件或目录,你不希望它们被纳入版本控制系统中。 比如编译生成的二进制文件、日志文件、临时文件或者是包含敏感信息的配置文件等等。 这些文件通常不需要被版本控制,因为它们要么是自动生成的,要么包含私密数据,不适合公开共享。
3 .gitignore和.gitkeep .gitignore 文件
.gitignore 文件就像是一个清单,告诉Git哪些文件和目录不需要被跟踪。 它可以帮你过滤掉那些不需要提交到仓库的文件,让仓库保持整洁,并保护隐私。创建 .gitignore 文件
假设你在项目根目录下创建一个名为 .gitignore 的文件,这个文件的名字前缀必须是一个点(.),表示这是一个隐藏文件。 在这个文件里,每行写一个模式,Git会根据这些模式来决定忽略哪些文件或目录。示例
假设你有一个Python项目,你可能不想将虚拟环境目录和一些日志文件加入版本控制。 你可以在项目的根目录下创建一个 .gitignore 文件,并添加以下内容: # 忽略Python虚拟环境 venv/ # 忽略日志文件 *.log # 忽略Thumbs.db文件(Windows系统) Thumbs.db 上面的.gitignore文件告诉Git忽略所有位于venv/目录下的文件和子目录,忽略所有扩展名为.log的文件,以及忽略名为Thumbs.db的文件。使用 .gitignore 文件
当你创建了一个新的.gitignore文件或修改了现有的文件后,Git会自动应用新的规则。 但是,如果某个已经被跟踪的文件现在被加入了.gitignore文件,Git不会自动删除该文件的历史记录。 你可以选择使用git rm --cached <file>命令来取消对文件的跟踪,但保留文件在本地磁盘上。.gitkeep 文件
有时候,你会有一些空的目录需要被Git跟踪,以便于保持项目结构清晰。 但是Git默认不会跟踪空目录。 为了告诉Git跟踪这些空目录,你可以在空目录内创建一个名为.gitkeep的文件。创建 .gitkeep 文件
创建一个空文件,命名为.gitkeep,然后把它放在你希望Git跟踪的空目录内。 这个文件的作用就是让Git知道这个目录不是真的空,而是有意留空的。示例
假设你有一个名为data的目录,它目前是空的,但是你希望Git能够跟踪这个目录的存在。 你可以在data目录内创建一个.gitkeep文件: mkdir data touch data/.gitkeep 这样,Git就会把这个空的data目录也纳入版本控制,保证项目结构的完整性。git patch 不是一个直接的Git命令,这里指的是使用Git来生成补丁文件(patch files),这些文件包含了对代码库的更改。 补丁文件是一种文本文件,它们包含了文件差异(diffs),可以用来在另一个副本中重现这些更改。
4 git patch 什么是补丁文件?
补丁文件是一个文本文件,它记录了两个文件或两个目录之间的一系列差异。 这些差异包括添加、删除或修改的行。 补丁文件可以应用于另一个相同或相似的文件或目录,从而将这些差异应用上去,达到“修补”的效果。Git生成补丁文件的方法
在Git中,你可以使用几种不同的命令来生成补丁文件。 最常用的是git diff 和 git format-patch 命令。使用 git diff
git diff 命令可以显示两个版本之间的差异,这些差异可以被重定向到一个文件中,成为补丁文件。 例如,如果你想要生成当前工作目录与最后一次提交之间的差异作为补丁文件,你可以这样做: git diff > mypatch.patch 这会生成一个名为 mypatch.patch 的文件,里面包含了当前工作目录与最后一次提交之间的差异。使用 git format-patch
git format-patch 命令则更加高级,它不仅可以生成补丁文件,还可以将补丁文件格式化为邮件格式,方便通过电子邮件发送给项目维护者或其他贡献者。生成单个补丁文件
如果你想要为当前分支上的最后一次提交生成一个补丁文件,可以使用如下命令: git format-patch HEAD~1 这将会在当前目录下生成一个补丁文件,文件名通常是 0001-<commit_message>.patch 格式。生成一系列补丁文件
如果你想要为一系列提交生成多个补丁文件,可以使用下面的命令: git format-patch <start-commit>..<end-commit> 例如,如果你想要为HEAD~5到HEAD之间的所有提交生成补丁文件,可以这样写: git format-patch HEAD~5..HEAD 这将在当前目录下生成一系列按顺序编号的补丁文件。应用补丁文件
一旦你有了补丁文件,你可以使用 git apply 命令来应用这些补丁。 例如,如果你有一个名为 mypatch.patch 的补丁文件,你可以这样应用它: git apply mypatch.patchgit squash 是一种在Git中合并多个提交成一个单一提交的技术。 想象一下,你在做一项复杂的任务时,可能会产生很多中间的提交,比如修复一个小bug、添加一些测试代码、调整样式等。 这些提交虽然一步一步地推动了项目的进展,但它们单独看起来可能显得杂乱无章。 使用git squash,你可以把这些相关的提交合并成一个干净、简洁的提交记录,使得你的提交历史更加清晰易读。
5 git squash 为什么使用 git squash?
整理提交历史 :有时候,你可能做了很多小的修改,这些修改最终构成了一个大的功能。 通过git squash,你可以把这些修改合并成一个逻辑上完整的提交,使得其他人查看你的提交历史时更加容易理解。保持历史简洁 :当你在进行开发时,可能会有一些实验性的提交或者一些临时的调试代码。 这些提交并不需要保留在最终的提交历史中,git squash 可以帮助你清理这些杂乱的部分。便于代码审查 :在团队协作中,提交历史的整洁程度直接影响到代码审查的效率。 通过git squash,你可以减少审查者的负担,让他们更容易集中注意力在重要的变更上。如何使用 git squash
git本身没有一个直接叫做git squash的命令,而是通过git rebase来实现git squash的效果。 下面是一个简单的步骤来演示如何使用git rebase来进行git squash:确保你在正确的分支上 :首先,确保你处于你想要合并提交的那个分支上。 git checkout my-feature-branch列出你想要合并的提交 :使用git log或者git reflog查看你想要合并的提交。开始交互式重新基线(rebase) :使用git rebase -i命令进入交互式重新基线模式,这里HEAD~n表示你想要合并的提交之前的提交,n是你想要保留的第一个提交。 git rebase -i HEAD~5 这会打开一个文本编辑器(通常是vim),显示一个列表,列出了你最近五次提交的SHA哈希值和提交信息。选择要合并的提交 :在编辑器中,你会看到每一行都以pick开头,后面跟着一个提交的SHA哈希值和提交信息。 对于你想要合并的提交,把pick改成squash或squash!,简称s。 比如: pick 7a61e01 添加功能A pick 1b40f0d 修复功能A中的bug pick 3a9c5f2 调整功能A的样式 pick 4d65220 添加功能B 改成: pick 7a61e01 添加功能A squash 1b40f0d 修复功能A中的bug squash 3a9c5f2 调整功能A的样式 pick 4d65220 添加功能B编辑合并后的提交信息 :当Git看到你选择了squash选项时,它会提示你编辑一个新的提交信息。 这个信息将代表你合并后的所有提交。 你可以在这里输入一个新的提交信息,或者编辑合并的提交信息。 # 编辑合并后的提交信息完成重新基线 :保存并关闭编辑器后,Git会执行合并,并将你带回到命令行。 此时,你已经成功地将多个提交合并成了一个。推送更改 :由于你改变了提交历史,所以需要推送分支到远程仓库时需要加上--force参数。 但是这通常是不建议的行为,git squash最好只用来处理本地分支,squash完毕之后再push到远端。 git push --force 通过这样的步骤,你可以将一系列的小提交合并成一个逻辑上连贯的大提交,使得你的Git提交历史更加整洁有序。 这对于保持良好的项目文档和提高团队协作效率是非常有帮助的。git submodule status 是一个用于检查Git子模块状态的命令。 子模块允许你在Git仓库中嵌入另一个Git仓库,就像在一个大项目中包含一个独立的库或组件一样。 子模块可以有自己的提交历史和版本控制,但它们被整合到主项目的版本控制流程中。 使用git submodule status可以帮助你了解这些子模块的当前状态,确保它们与你期望的状态一致。
6 git submodule status 什么是Git子模块?
在开发过程中,你可能会用到一些外部库或工具,这些库或工具本身就是独立的Git项目。 例如,你可能在构建一个Web应用时,需要用到一个第三方的JavaScript库。 在这种情况下,你可以将这个库作为一个子模块添加到你的主项目中,这样你的项目就包含了这个库的所有源码和历史记录。为什么要使用 git submodule status?
当你在一个项目中有多个子模块时,了解这些子模块的状态是非常重要的。 这包括知道它们是否已经初始化,是否有未提交的更改,是否与远程仓库同步等。 git submodule status 命令提供了这些信息,帮助你更好地管理子模块。 git仓库中保存了主仓库和子仓库的对应关系,这些关系往往是非常重要的,不同仓库的版本必须严格对应,使用git submodule status 命令可以快速得知当前主仓库的提交对应哪些子仓库的提交。如何使用 git submodule status
使用git submodule status命令,你可以查看所有子模块的状态。 命令非常简单: git submodule status 执行这个命令后,你将看到一个列表,每个子模块对应一行,每一行包含以下信息:SHA-1 哈希值 :这是子模块当前指向的提交的哈希值。子模块路径 :这是子模块在你的项目中的位置。 状态标志 :这一列会显示子模块的状态。 如果一切正常,通常会看到一个空格。 如果有变化,则会显示相应的状态标志,例如: +:表示子模块的本地版本比其记录的版本超前。 -:表示子模块的本地版本落后于其记录的版本。 D:表示子模块的本地版本与记录的版本有分歧。 A:表示子模块已被添加但尚未初始化。 I:表示子模块已初始化。 R:表示子模块的URL已被更改。示例
假设你有一个项目,其中包含了一个名为third-party-library的子模块。 你可以这样查看它的状态: $ git submodule status 166d2f8b3e83893f9d150c19d6f02b279e490639 third-party-library (HEAD detached at v1.2.3) + 这表明子模块third-party-library当前指向的提交是166d2f8b3e83893f9d150c19d6f02b279e490639,并且本地版本比记录的版本超前(因为有+标志)。git blame 是一个非常有用的命令,它帮助你追踪某一行代码是谁在什么时候修改的。 想象一下,你正在阅读一个复杂的代码文件,突然发现了一个问题,可能是某个功能不再工作了,或者某个变量的值看起来不对劲。 这时候,你可能会想知道:“这一行代码是谁写的?是什么时候改的?为什么这么改?” git blame 就是用来回答这些问题的。
7 git blame 什么是 git blame?
git blame 命令显示了每一个文件行的最后修改者及其修改的时间戳和提交信息。 这就像给每一行代码打上了标签,告诉你这行代码是由谁在哪个提交中引入或修改的。为什么使用 git blame?
查找修改者 :当你发现一个问题时,可以通过git blame找到最后修改那行代码的人,从而更容易地定位问题的原因。了解历史 :通过查看某一行代码的修改历史,你可以了解为什么代码被这样编写,这对理解代码逻辑和意图非常有帮助。代码审查 :在团队协作中,git blame 可以帮助审查代码的变更,确保代码质量。如何使用 git blame
使用git blame非常简单,基本语法如下: git blame [options] <file> [options]:你可以添加一些选项来定制输出,比如限制显示的行数或显示完整提交信息。 <file>:这是你要查看的文件名。基本用法
如果你想查看某个文件的每一行最后被谁修改,可以直接运行: git blame <file> 例如,如果你有一个名为app.js的文件,你可以这样查看: git blame app.js 输出结果会显示每一行代码对应的提交信息,包括提交者的姓名、日期和提交的摘要信息。示例输出
假设你运行了git blame app.js,输出可能是这样的: 9e15a148 (Alice Smith 2024-01-01 10:30:00 +0800) 1: function greet() { 9e15a148 (Alice Smith 2024-01-01 10:30:00 +0800) 2: console.log('Hello!'); c6f3b47a (Bob Lee 2024-01-02 14:15:00 +0800) 3: // Added a comment for clarity. 9e15a148 (Alice Smith 2024-01-01 10:30:00 +0800) 4: } 每一行的输出包含以下信息: SHA-1哈希值(如9e15a148):这是最后一次修改该行的提交的唯一标识符。 提交者的姓名(如Alice Smith)。 提交的日期和时间(如2024-01-01 10:30:00 +0800)。 提交信息摘要(如function greet())。 行号(如1:)。 实际的代码行内容。更多选项
git blame 还支持许多选项来定制输出,例如: 如果你想查看app.js文件第5行到第10行的修改历史,可以这样运行: 1git blame -L 5,10 app.js实际场景中的应用
假设你在开发一个Web应用,突然发现用户登录功能出现了问题。 你不确定是什么时候引入的这个问题,也不知道是谁修改了这部分代码。 你可以使用git blame来追踪: 找到出现问题的文件,比如login.js。 运行 git blame login.js 查看每一行的修改记录。 发现第15行的代码有问题,然后看到这条记录是由Bob在两天前的提交中修改的。 通过这种方式,你可以快速定位问题的来源,并联系Bob询问他当时的修改原因,从而更快地解决问题。想象一下,在一个大型工程中,一次编译会产生非常多的产物,这些产物可能都会影响到了仓库状态,而如果我们只想关注哪些源文件发生了变化,这个时候应该怎么办呢? 我们可以通过git status + grep命令来解决这个问题。 git status --short | grep '\.(c|h)$' git status --short:输出一个简洁的格式,每行包含一个状态代码和文件名。 grep '\.(c|h)$':筛选出以.c或.h结尾的文件。
8 git status | grep ... 在日常的开发工作中,Git是我们不可或缺的好帮手,它帮助我们管理代码的版本、协同工作并追踪每一次的改动。 从确保与远程仓库同步的git remote update,到临时保存工作进度的git stash;从避免不必要的文件被纳入版本控制的.gitignore和.gitkeep,到生成补丁文件以便审查和应用的git patch;从整理提交历史、使代码审查更加清晰的git squash,到管理子模块状态的git submodule status;再到追踪代码修改源头的git blame,以及快速筛选特定文件改动的git status | grep
结语